У вас есть одно большое дерево, в котором хранится все состояние (state) приложения - это хранилище (store).
Также у вас есть набор редьюсеров (которые скомбинированы в один общий rootReducer) - это функции, который принимают текущее состояние и действие и возвращают новое состояние:
function someReducer(state = initialState, action) {
// обычно выглядит как switch
// action - простой js-объект
// и обязательно имеет строковое поле type
switch(action.type) {
// обрабатываем действие с типом SOME_ACTION_NAME
case 'SOME_ACTION_NAME':
// берем какие-то данные из экшена и возвращаем новое состояние
// при этом менять sate нельзя!
// state.someProperty = action.newStateData <--- НЕТ!
return { ...state, action.newStateData };
// Если мы не обрабатываем действие - просто возвращаем старое состояние
default:
return state;
}
}
Также есть экшен креаторы (actionCreators) - это функции, которые возвращают действие. затем это действие вещается в хранилище (диспатчится). Типичный пример:
function someActionCreator(someArg) {
return {
type: 'SOME_ACTION_NAME',
newStateData: someArg + 5, // <-- разная логика
};
}
По-умолчанию в качестве экшена мы можем вернуть только простой объект, но при создании хранилища можно добавить так называемый middleWare. Это специальные функции, которые принимают все экшены из диспатча и могут передавать их дальше (при этом содержат дополнительную логику).
Если мы хотим получить доступ к состоянию в экшен креаторе - воспользуемся thunkMiddleware:
import thunkMiddleware from 'redux-thunk';
function createStore(initialState) {
const reducer = combineReducers(reducers);
const finalCreateStore = applyMiddleware(
thunkMiddleware // <-- добавляем middleware
)(defaultCreateStore);
return finalCreateStore(reducer, initialState);
}
Теперь мы можем делать так:
function someActionCreator(someArg) {
return (dispatch, getState) => { // <-- возвращаем фукнцию, а не объект!
const someState = getState().reducerName;
return {
type: 'SOME_ACTION_NAME',
newStateData: someArg + someState,
};
};
}
В общем схема выглядит так:
actionCreator --action--> dispatch --action--> middleware --action--> store --action--> reducer --> newState
Затем мы берем из
react-redux метод connect, который подключает Ваш умный компонент к хранилищу:
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
class MyComponent extends Component {
static propTypes = {
someProp: PropTypes.string.isRequired,
someFunc: PropTypes.func.isRequired,
};
}
// Тут мы берем из глобального состояния необходимую нам часть
// В ownProps - свойства компонента. Тут могут быть например свойства от роутера
function mapStateToProps(state, ownProps) {
return {
someProp: state.someReducer,
};
}
function mapActionsToProps(dispatch) {
return bindActionCreators ({ // <-- биндим все на disptach для удобства
someFunc: (someArg) => someActionCreator(someArg + 1),
}, dispatch);
}
export default connect(
mapStateToProps,
mapActionsToProps
)(MyComponent);