Translate

Поиск по этому блогу

Показаны сообщения с ярлыком Redax. Показать все сообщения
Показаны сообщения с ярлыком Redax. Показать все сообщения

воскресенье, 5 июля 2020 г.

Следует ли использовать React Context поверх Redux в приложении React?







Redux - это библиотека, которая помогает управлять состоянием вашего приложения.

Redux следует использовать в средних и больших одностраничных приложениях со сложным потоком данных.

Redux может добавить ненужную сложность вашему приложению, если оно действительно маленькое с простым потоком данных.

С другой стороны, в версии 16.3 React команда представила Context, который также помогает управлять состоянием React - приложения.

Зачем нам нужен инструмент управления состоянием - state

Если у нас есть несколько компонентов, которые совместно используют один и тот же фрагмент данных, и у них нет родительских и дочерних отношений, то для решения проблемы используют Redux. В Redux у нас есть один фрагмент идентичных данных (identical data), который синхронизирован со всеми компонентами, которые используют этот фрагмент данных.

Одним из решений может быть использование event raising в Angular и использование props в React. Позже в большом коде это решение превратится в спагетти событий ( event spaghetti) и в React - приложении, мы будем сталкиваться с проблемой получения (доступности) props - так называемым - prop drilling.

Со всей базы кода мы начнем получать события, и будет сложно отслеживать их все. Таким образом, поток данных становится непредсказуемым. Facebook столкнулся с этой проблемой еще в 2014 году, поэтому они представили Flux Architecture.

Redux - это упрощенная и легкая реализация Flux Architecture.

Основные преимущества Redux

  • Отделенная, расцепленная архитектура
  • Тестируемость
  • Отличная поддержка инструментов в Chrome, Firefox
  • Простая реализация функций отмены / повтора - выкл./вкл.


Когда использовать Redux

В следующих случаях мы можем использовать redux:
  • Один и тот же фрагмент данных в нескольких местах
  • Несколько (views) - представлений, которые должны работать с теми же данными в синхронизации
  • Данные могут быть изменены несколькими действиями / несколькими пользователями


Прежде чем мы получим context, для решения проблемы использовали redux, такой как спагетти - event spaghetti и prop drilling. Redux приносит много сложности для простых приложений. Позже React - команда представила контекстную концепцию для простоты.

С помощью контекста - context мы можем передавать данные по нашему дереву компонентов без prop drilling. Таким образом, в одном компоненте мы предоставим некоторый контекст или общие данные, а в другом компоненте мы будем использовать данные.

Теперь мы увидим, как мы можем использовать контекст поддерживаемым и инкапсулированным образом с помощью typescript и React - хуков. В нашем примере мы будем использовать понятия действий - actions, редуктора - reducer и состояния - state из redux. Итак, сначала мы рассмотрим основные концепции Redux.

Основная концепция Redux

  • Хранилище - Store - один объект JS, который содержит состояние приложения.
  • Действия - Actions - Обычный объект JS, представляющий, что что-то произошло. Подобные события.

  • {type: ‘USER_LOGGED_IN’}

  • Редуктор Reducer- функция, которая определяет, как состояние state изменяется в ответ на действие - action. Это не меняет состояние. Возвращает новое состояние.
В Redux мы не обновляем напрямую состояние. Сначала мы отправим действие (action). Оно попадет в хранилище (store). Хранилище (store) передает действие (action) корневому редуктор (reducer). На основе действия редуктор (reducer) возвращает новое состояние (state), и хранилище (store) обновляется внутри.


На картинке показано изменение состояния компонента при клике


Использование контекста в приложении React

Для демонстрации идея состоит в том, чтобы создать компонент ,mark>Header, который будет отвечать за отображение кнопки «Вход» или «Выход из системы» в зависимости от состояния из хранилища - store. Мы отправим действие action LOGIN и LOGOUT из компонента Header.

Мы сделаем все 5 простых шагов.
  1. Create Actions - Создать действия
  2. Create State - Создадим состояние
  3. Create Reducer - Создадим редуктор
  4. Create Context - Создадим контекст
  5. Create Header component - Создадим сам компонент Header

1 - Создание действий - Actions

Сначала мы должны определить некоторые действия, которые будут отвечать за изменение состояния нашего приложения. У нас есть два действия "Войти" и "Выйти".

Action.ts
export enum Action {
  LOGIN = "LOGIN",
  LOGOUT = "LOGOUT"
}


Создание состояния - State

Теперь мы должны определить, какие данные мы хотим сохранить в нашем хранилище контекста. Поэтому мы создадим интерфейс для этого, а также начальное значение для состояния. В нашем случае мы просто сохраним имя пользователя.

state.ts
export interface StateType {
  username: string | null;
}
export const initialState: StateType = {
  username: null
};


Создание редуктора - Reducer

Pure Function или Чистая функция - это такая функция, которая при получении однинх и тех же данных на входе, всегда получаем один и тот же выход из функции, то функция является чистой функцией. Так что побочных эффектов не будет. Это дает нам легкую тестируемость и простой способ реализации функций отмены / возврата.
Если вы забыли некоторые возможности JavaScript, то я рекомендую вам посмотреть статьи в моем блоге - ES6 и JS
Далее мы создадим редуктор. Редуктор это чистая функция. Это функция с двумя аргументами. Первый - это состояние по умолчанию с типом StateType, а второй - объект с props- свойствами type и полезной нагрузки - payload. Свойство type определяет тип действия, а payload содержит дополнительные данные от диспетчера.

Reducer.ts
import { StateType, initialState } from "./state";
import { Action } from "./Action";
export type ActionType = {
  type: Action;
  payload?: StateType;
};
const reducer = (state: StateType, { type, payload }: ActionType) => {
switch (type) {
    case Action.LOGIN:
      return { ...state, ...payload };
  
    case Action.LOGOUT:
      return initialState;
default:
      return state;
  }
};
export default reducer;


Для action -действия LOGIN мы передадим имя пользователя в качестве полезной нагрузки - payload, когда мы отправим действие - action. Для выхода из системы нам не нужны никакие данные в качестве полезной нагрузки -payload. Мы просто сбросим состояние до начального значения state.

4 - Создадим контекст -Context

Теперь мы создадим контекст. Сначала мы определим ContextType, а затем создадим Store. После этого мы создадим StoreProvider.

Context.tsx
import React, { createContext, Dispatch, useReducer } from "react";
import reducer, { ActionType } from "./Reducer";
import { StateType, initialState } from "./state";
export interface ContextType {
  state: StateType;
  dispatch: Dispatch<ActionType>;
}
export const RootStore = createContext({} as ContextType);
export const RootStoreProvider: React.FC = ({ children }) => {
const [state, dispatch] = useReducer<React.Reducer<StateType, ActionType>>(reducer, initialState);
const value = { state, dispatch };
return <RootStore.Provider value={value}>{children}</RootStore.Provider>;
};


Теперь мы обернем наш корневой компонент этим RootStoreProvider для доступа к хранилищу - store глобально.

index.tsx
const App = () => {
  return <RootStoreProvider>....</RootStoreProvider>;
};



Теперь у нас все готово. Мы создадим простой компонент Header, из которого мы будем использовать RootStore для получения информации о пользователе, а также для обновления информации.

5 - Создадим сам компонент Header



Header/index.tsx
import React from "react";
const Header = () => {
  const username = null;
  const toggleLoginLogoutHandler = () => {};
  return (
    <div
      style={{
        backgroundColor: "#dee5ec",
        padding: 10,
        display: "flex",
        justifyContent: "space-between",
      }}
    >
      <div>
        <p>Header</p>
        {username && <p>Logged in as {username}</p>}
      </div>
      <button onClick={toggleLoginLogoutHandler}>
        {username ? "Logout" : "Login"}
      </button>
    </div>
  );
};
export default Header;



Теперь мы будем использовать наш RootStore для получения имени пользователя, а также для отправки действий по входу и выходу из системы.

import React, { useContext } from "react";
import { RootStore } from "../../Context";
import { Action } from "../../Action";
const Header = () => {
  const {
    state: { username },
    dispatch
  } = useContext(RootStore);
const toggleLoginLogoutHandler = () => {
    if (username) {
      dispatch({ type: Action.LOGOUT });
    } else {
      dispatch({ type: Action.LOGIN, payload: { username: "Ashraful" } });
    }
  };
.......


Наконец, обновите корневой компонент.

.......
import Header from "./src/components/Header";
const App = () => {
  return (
    <RootStoreProvider>
      <Header />
    </RootStoreProvider>
  );
};


Вот и все. Мы внедрили React context со всеми концепциями Redux - компонентов. Вот ссылка на полный код.







Хотите освоить самые современные методы написания React приложений? Надоели простые проекты? Нужны курсы, книги, руководства, индивидуальные занятия по React и не только? Хотите стать разработчиком полного цикла, освоить стек MERN, или вы только начинаете свой путь в программировании, и не знаете с чего начать, то пишите через форму связи, подписывайтесь на мой канал в Телеге, вступайте в группу на Facebook. Пишите мне - kolesnikovy70 почта gmail.com


Удачного кодирования!                                                                                                                                                              

Телеграм канал - Full Stack JavaScript Developer
Помочь проекту (любая валюта). DONATE

среда, 26 декабря 2018 г.

Redux - простое руководство.

Пришло время разобраться с Redux и написать простое приложение с его использованием.




Посмотреть готовое приложение можно на хосте.

Я не буду долго рассказывать зачем он нужен и как он работает. В сети есть масса информации.

Остановлюсь только на том, что Redux используется для работы с данными. В библиотеке React нет простых методов для работы с данными и в больших приложениях это часто вызывает трудности.

Для простоты доступа к данным и работы с ними, мы будем использовать Redux.



Стоит напомнить, что Redux использует Flux архитектуру (не путайте с Flux-библиотекой, которая тоже использует такую архитектуру). Flux предполагает однонаправленный поток данных - One-way binding

Для простоты понимания этого, стоит посмотреть на картинку <<Схема>>:



Справа, квадратик у нас имеет подписью View. Это и есть те компоненты, которые вы непосредственно создаете в React и которые в перспективе будут отражать дрянные на экране монитора. В браузере эти компоненты получают данные из Store.

Store - это хранилище и именно так его нужно понимать в данном контексте. По своей сути Store - это обыкновенный объект, который и определяет, как у нас будет выглядеть наши компоненты.

Важный момент заключается в том, что Store является единственным и общим хранилищем для всех наших компонентов и в будущем когда у вас будет увеличиваться и разрастаться, это будет очень удобно, потому что вы сможете легко контролировать процесс распределения свойств.

Далее, у нас идёт Dispatcher. Dispatcher это центральный узел, который обрабатывает все наши потоки данных. То есть - всё проходит через него! А конкретно, через него проходит те данные, которые определяют как раз-таки action.

Значит есть один action (слева на картинке). Этот Action у нас стоит самого начала и считаете это теми данными которые идут по умолчанию. То есть, по умолчанию поступает какие-то данные в Action говорит диспетчеру - "Покажи мне Username такой-то и Lastname такой-то!". И диспетчер заносит изменения в Store, откуда они подтягиваются View (React -components) и мы видим картинку на экране.

В тоже время, если мы хотим поменять нашу визуальную картинку со стороны пользователя, мы так же создаем новый Action. Новый Action, который опять обращается к диспетчеру и делает тоже самое. Говорит диспетчеру "Обнови username Коля на username Вася" и он его обновляет. Это определяет уже наш View.

Вот в этом собственное заключается вся суть архитектуры Flux и самого принципа One Way binding, то есть однонаправленного потока данных. Если вы заметили, то у нас поток данных идёт всегда в одну сторону!

View не может непосредственно повлиять на что-то, что есть в нашим хранилище! Это главное отличие его от так называемого Two-way binding, например, который использует ангуляр.

Действия загрузки данных.

Передача данных.

Для простоты, мы будем использовать готовое решение create-react-app. Как его установить я рассказывал в своих постах о React Переходим в папку нашего приложения и устанавливаем два дополнительных модуля:
  1. redux
  2. react-redux
Эти модули позволят нам использовать весь функционал Redux и просто совместить его с React.

npm install redux react-redux


--save-dev команду можно не писать.

После установки, мы можем открыть наш проект в редакторе.

Выбираем файл index.js в папке src - это точка входа в наше приложение.

Импортируем компонент Provider из модуля react-redux

import { Provider } from "react-redux";

Данный компонент является оберткой для нашего приложения и позволяет получать компонентам свойства из Store, поэтому следующим шагом нам нужно обернуть компонент App в Provider.


ReactDOM.render(<Provider>
                    <App />
                </Provider>, document.getElementById('root'));


Следующее, что нам нужно сделать, это импортировать функцию, которая и создает Store.

import { createStore } from 'redux';

Для создания хранилища - Store напишем:

const store = createStore(()=>{});

В качестве параметра эта функция должна принимать reducer. Сам по себе редусер - это просто функция, поэтому мы для начала, можем записать вместо него , пустую функцию, например стрелочную - ()=>{}.

Для соединения провайдера с хранилищем Store, мы добавим Provider атрибут store, со значением store.


ReactDOM.render(<Provider store={store}>
                    <App />
                </Provider>, document.getElementById('root'));


Таким образом, мы создали Store, обернули его в провайдер и сделали данные доступные для наших компонентов.

Создание Reducers.

В папке src создадим папку reducers и в ней два файла index.js и info.js.

Reducer по своей сути это функция. Эта функция запускается каждый раз, когда мы отправляем какое-то действие. Пользовательского действия у нас пока не будет, а будет действие- инициализации ( т.е. начало работы нашего приложения).

Сам термин пришел к нам из JS Array.prototype.reduce().

Вся суть редусера - это взять предыдущее, значение, плюс текущее значение и в конце - вернуть новое значение.

То есть, мы берем предыдущее состояние State, то что нам нужно поменять, соединяем это и получаем что-то новое, что в последствии у нас отрендерится на экране.

Создадим первый редусер в файле info.js


// имитация базы данных
const initialState = {
    user: "unknown user"
}
//  сам редусер 
export default function userInfo (state = initialState) {
    return state
}


Функция принимает в качестве стандартного значения - initialState и возвращает новый state на основании старого.

Проще говоря редусер принимает один state, а возвращает новый state.

Файл index.js в папке reducers, нам потребуется для того, чтобы все редусеры держать в одном месте, но в разных файлах. В качестве "родительского" редусера мы будем использовать index.js. В этом нам поможет, то что уже реализовано в библиотеке Redux - combineReducers


import { combineReducers } from "redux"
import userInfo from "./info"

const rootReducer = combineReducers({
  userInfo
})

export default rootReducer;



Теперь, самое время вернуться в файл index.js в корне проекта, и заменить анонимную, пустую функцию на rootReducer. И добавим импорт редусеров в наш файл.


import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

import { Provider } from "react-redux";
import { createStore } from "redux";
import rootReducer from "./reducers/index";

const store = createStore(rootReducer);

ReactDOM.render(<Provider store={store}>
                    <App />
                </Provider>, document.getElementById('root'));
serviceWorker.unregister();



Таким образом наш Store, будет знать, что когда мы к нему обращаемся, то он будет вызывать все редусеры, которые у нас есть.

Store по своей сути, это просто обычный объект, который содержит State для всего нашего приложения. То есть всё, что у нас может изменяться, обо всём этом должен знать State и он это регулирует.

Фактически, мы сейчас с помощью нашей функции в редусере ( function userInfo ), занесли в наш State данных переменной user со значением "unknown user". Теперь осталась нам подключить наш компонент к этому Store и взять с него то что принадлежит нам по праву, а именно наши свойства.

App.js


import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

import { connect } from "react-redux"

class App extends Component {
  render() {
    return (
          <h2>Welcome to React</h2>
    );
  }
}


export default connect()(App);



Чтобы подключить Redux к компоненту есть специальная функция - connect

Подключаем ее:

import { connect } from "react-redux";

Она работает очень просто. В том месте, где мы экспортируем наш компонент, просто дописываем эту функцию и в скобках прикрепляем к ней наш компонент:

export default connect()(App);

Если сейчас запустит и посмотреть приложение:



Здесь можно видеть, что функция connect создает дополнительный компонент над компонентом App.

Передача свойств приложению.

Для передачи свойств приложению:

App.js

import React, { Component } from 'react';

import './App.css';

import { connect } from "react-redux"

class App extends Component {
  render() {
    return (
          <h2>Welcome to React {this.props.user}</h2>
    );
  }
}

function mapStateToProps(state) {
  return {
    user: state.userInfo.user
  }
}

export default connect(mapStateToProps)(App);



Создаем дополнительную функцию mapStateToProps. Название произвольное, но оно рекомендуется, чтобы другие разработчики понимали то, что делает эта функция. Эта функция будет передавать наши state в свойства. Функция принимает наш state, а возвращать будет некую переменную ( для логичности - user), а в качестве значения возьмем те данные, которые указали на данный момент в редюсере.

Чтобы обратится к этим данным, нам нужно обратиться к нашему state, с которого мы подтягиваем данные. Дaлее к userinfo из rootReducer и уже используя userinfo мы попадаем в наш изначальный редусер и получаем доступ к значению переменной user в файле info.js.

user: state.userInfo.user

И чтобы эта функция заработала, мы должны ее передать, в качестве аргумента, в функцию connect.



Таким образом мы с помощью функции передали в компонент App свойство user со значением unknown user

Мы смогли передать те значения, которые мы изначально несли в нашу "Базу данных" - const initialState.

Вывести свойства на экран нам легко - {this.props.user}

Практически, мы получили тоже самое, как если бы передали свойство user={"unknown user"} непосредственно в компонент реакт.

Псомотреть весь код приложения, можно в репо - redux-simple-abc ci -m"Simple data transfer with Redux"

Действия пользователя.

Действия - Actions

Все что мы делали ранее не относилось к действиям пользователя. Если следовать второй картинке этого поста, то мы разбирали работу Action, который слева на картинке.

Действия пользователя будут представлены в Action, который на картинке <<Схема>> вверху.

Важно запомнить, что Action определяют что именно нужно поменять, а Reducer - как именно.


Для лучшего понимания работы редусеров, следует вспомнить, как различаются компоненты в React:



Согласно этой схеме, нам стоит разделить наше приложение на контейнеры и компоненты. Это поможет правильно разделить логику нашего приложения и в будущем, когда приложение разрастется, это поможет легко его поддерживать.

В папке src создадим папки: containers и components.

В папке components создадим: User.js и Year.js

В файле User.js создадим простой, глупый компонент - Dumb Component:


import React from "react"
export default class User extends React.Component {
  render() {
    return (
      <h2>Welcome to React {this.props.user}</h2>
    );
  }
}



Его render() мы взяли из файла App.js.

В файле Year.js мы создадим несколько кнопок, для возможности выбора пользователем, соответствующего года.


import React from "react"

export default class Year extends React.Component {
  constructor(props) {
    super(props)
    this.onBtnClick = this.onBtnClick.bind(this)
  }

  onBtnClick(event) {
    return this.props.setYear(event.target.textContent)
  }

  render() {
    return <div>
      <button onClick={this.onBtnClick}>1975</button>
      <button onClick={this.onBtnClick}>1991</button>
      <button onClick={this.onBtnClick}>2015</button>
      <p>This year has been chosen - {this.props.year}</p>
    </div>
  }
}



Если коротко, то создали компонент, который будет выводит кнопки. На кнопки навесили событие onClick, которое вызывает функцию onBtnClick. В конструкторе прибиндили эту функцию. Эта функция возвращает функцию setYear(), которая в качестве аргумента принимает значение кнопки (текст кнопки - в данном случае год) - event.target.textContent.

Таким образом мы написали два dumb-компонента.

Теперь нам нужно поменять файл App.js

Поскольку он у нас будет выполнять функцию smart - компонента, мы переместим его в папку src/containers

Так как мы поменяли директорию файла App.js, то в файле нам нужно изменить путь подключения его в файле index.js в корне сайта.

import App from './containers/App';

На этом этапе нам нужно запустить приложение, чтобы убедиться, что оно по прежнему работает.



Посмотреть весь код приложения на этом этапе, можно в репо - redux-simple-abc ci -m"divided the application into components"

Теперь нам необходимо в наш smart - компонент App.js добавить наши dump-компоненты - User.js и Year.js


    import React, { Component } from 'react';
    import './App.css';
    import User from '../components/User';
    import Year from '../components/Year';
    import { connect } from "react-redux"

    class App extends Component {
      render() {
        return (
           <div>
            <User />
            <Year />
          </div>
              
        );
      }
    }

    function mapStateToProps(state) {
      return {
        user: state.userInfo.user
      }
    }

    export default connect(mapStateToProps)(App);


Если сейчас посмотреть в браузер, то мы увидим:



Вывели на экран все статические данные, кроме необходимых переменных.

Переменная user не задействована в экшенах и мы ее можем легко отобразить прямо сейчас:

<User user={this.props.user} />



Эту переменную мы не меняем в нашем приложении и вывод ее на экран это просто свидетельство того, что Redux работает.

Все действия будут происходить в компоненте Year.js и для того, чтобы их увидеть, нам нужно создать экшен.

В папке src создаем папку actions а в ней файл actionYear.js


export default function setYearAction(year) {
    return {
      type: "SET_YEAR",
      payload: year
    }
  }



Экшен по своей сути это обычный объект. Для удобства их создают через специальные функции, которые называются Action Creators. Это упрощает чтение кода и очень удобно для разработки!

Название функции setYearAction - произвольное, но лучше, если оно будет понятным.

Функция обязательно возвращает объект и в нем должно быть обязательно поле - type.

Поле - type, чем то похоже на идентификатора экшена, и значение этого поля всегда строка с заглавными буквами - UPPERCASE.

Вторая переменная payload, будет принимать значение year то, которое мы передаем в эту функцию изначально.

payload - тоже вне гласное соглашение. Обозначает что-то типа "полезной нагрузки".

Более подробно о формате написания экшенов можно почитать в стандартах - Flux Standard Action

Как мы говорили ранее - экшен - ЧТО МЕНЯЕМ... А мы меняем -year, который в аргументе и меняем его экшеном - "SET_YEAR"

Теперь нам нужно понять КАК нам его изменить.

За это у нас отвечает редусер.

Переходим в редусеры src/reducers/info.js и будем его усовершенствовать.

Добавим некий изначальный стейт - например: year: 2015, а в самом редусере добавим еще один аргумент - action

Таким образом редусер будет принимать начальное состояние: state = initialState и то, что должно измениться - action, все это соединяет и возвращает нам новый стейт на основании проделанной работы.

Обычно их указывают в формате switch/case.

В нем обратимся к типу экшена и обработаем различные варианты.

Если у нас тип = "SET_YEAR", то мы возвращаем весь предыдущий стейт ( ...state) и ключ year с новым значением action.payload.

Другими совами: Мы берем наш изначальный стейт :

reducers/info.js

const initialState = {
    user: "unknown user",
    year: 2015
}



Вторым аргументом берем стейт из экшена: actions/actionYear.js
export default function setYearAction(year) {
    return {
      type: "SET_YEAR",
      payload: year
    }
  }



Соединяем их вместе и получаем что-то новое! А конкретно - изменяем поле year на то, которое указано в экшене.

Теперь нашей задачей является - доделать наш "умный компонент", который должен отправлять данные в Store.

Переходим в src/containers/App.js

Первое - импортировать функцию из actionYear.js

import setYearAction from '../actions/actionYear';

Выведем год статически:


    import React, { Component } from 'react';
import './App.css';
import User from '../components/User';
import Year from '../components/Year';
import setYearAction from '../actions/actionYear';
import { connect } from "react-redux";

class App extends Component {
  render() {
    return (
      <div>
        <User user={this.props.user} />
        <Year year={this.props.year}/>
      </div>
          
    );
  }
}

function mapStateToProps(state) {
  return {
    user: state.userInfo.user,
    year: state.userInfo.year
  }
}

export default connect(mapStateToProps)(App);


Посмотрим в браузере:



Таким образом мы вывели "стартовые значения" стейта.

Теперь нам нужно оживить наши кнопки!

Для этого нам нужно передать новые данные диспетчеру, а он их добавит в Store.

Для этого есть специальная функция - mapDispatchToProps(dispatch) .Она принимает аргумент - dispatch и возвращает некий объект.


function mapDispatchToProps(dispatch) {
  return {
    setYearFunction: year => {
      dispatch(setYearAction(year))
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(App);



setYearFunction - произвольное название. Мы выбрали его, чтобы просто отличать функцию от других. В качестве ключа в нее мы передаем функцию, которую мы записали в стрелочном формате. Эта функция принимает аргумент year, который передаст наш экшен actionYear и с ним мы в функции dispatch() вызываем экшен креатор. - setYearAction(year) и в качестве аргумента ей передадим тот же year

В нижней строке мы просто подключили ее, указав в качеств аргумента через запятую.

Если посмотреть в браузер, то в панели разработчика мы увидим:



Поскольку мы подключили в наш компоненту новую функцию - mapDispatchToProps она передала в наш компоненте новое свойство - setYearFunction (как мы его и назвали в этой функции)

Теперь для того, чтобы нам ее использовать, нам не нужно делать ничего сложного, а просто получить доступ к этому свойству.

В файле App.js передадим компоненту Year напишем свойство, которому передадим функцию setYearFunction из ретурна mapDispatchToProps

<Year year={this.props.year} setYear={this.props.setYearFunction} />

this.props - пишем, потому что функция передается в качестве свойства.

Теперь становится ясным, что в функции onBtnClick мы как раз и возвращаем это свойство со значением текста кнопки:

Файл: components/Year.js

 onBtnClick(event) {
    return this.props.setYear(event.target.textContent)
  }



Теперь самое время посмтреть наше приложение и проверить, что все работает правильно:



Коротко:

Все начианется в нашем компоненте - Year.Здесь есть кнопки, при нажатии на которые срабатывает функция onBtnClic

Эта функция возвращает нам event.target.textContent - то есть в данном случае это текст кнопки.

Далее эти данные попадают в функцию mapDispatchToProps(dispatch) и в ней уже year будет равен тому, что мы указали в компоненте и функция dispatch(setYearAction(year)) отправляет наш экшен в хранилище -Store с помощью метода connect(mapStateToProps, mapDispatchToProps)(App)

В Store запускается редусер.Он принимает начальный стейт и экшен, который ему прислал mapDispatchToProps(dispatch), срабатывает условие - "SET_YEAR" и year меняет значение на новое - action.payload.

Далее возвращается в приложение функцией mapStateToProps(state) и мы получаем доступ к этим данным.

Посмотреть весь код приложения, можно в репо - redux-simple-abc ci -m"Finish"





                                                                                                                                                             


Хотите освоить самые современные методы написания React приложений? Надоели простые проекты? Нужны курсы, книги, руководства, индивидуальные занятия по React и не только? Хотите стать разработчиком полного цикла, освоить стек MERN, или вы только начинаете свой путь в программировании, и не знаете с чего начать, то пишите через форму связи, подписывайтесь на мой канал в Телеге, вступайте в группу на Facebook.Пишите мне - kolesnikovy70 почта gmail.com