function removeFromStructure(id) {
return { type: REMOVE_FROM_STRUCTURE, paylodad: id }
}
function doSomething(id) {
return { type: DO_SOMETHING, paylodad: id }
}
function commonAction(structureObject) {
return structureObject.blockId ? removeFromStructure(id) : doSomething(id)
}
const action = {
id: 132,
_key: 'some key',
_value: 564
}
return {
...state,
structure: {
...state.structure,
[id]: { ...(state.structure[id] || {}), ...action },
}
}
...(state.structure[id] || {})
import _ from 'lodash'
const { id, parentId } = action
// удаляем из структуры свойство с именем id
const nextStructure = _.omit(state.structure, id)
return {
...state,
structure: {
...nextStructure,
[parentId]: {
...nextStructure[parentId],
childIds: nextStructure[parentId].childIds.filter(cId => cId !== id)
}
}
}
const { id, parentId } = action
// в данном случае у нас будет переменная
// const removed = state.structure[id]
// а в переменную nextStructure попадут все значения, кроме id
const { [id]: removed, ...nextStructure } = state.structure
return {
...state,
structure: {
...nextStructure,
[parentId]: {
...nextStructure[parentId],
childIds: nextStructure[parentId].childIds.filter(cId => cId !== id)
}
}
}
shouldComponentUpdate(nextProps, nextState) {
return shallowCompare(this, nextProps, nextState);
}
const store = createStore(history, client, initialState)
store.dispatch(appActions.loadInitialData())
render((
<Provider store={store}>
<Router history={finalHistory}>
{routes}
</Router>
</Provider>
), reactRootElement)
function loadInitialData() {
return dispatch => axios
.get(`${apiPrefix}/entities`)
.then(entities => dispatch(saveEntities(entities)))
}
const myReducer = combineReducers({ connectedReducer1, connectedReducer2 })
function combinedReducer(state = initialState, action = {}) {
switch(action.type) {
case SOME_COMPLEX_ACTION:
return {
...state,
someProp: someOtherReducer(state.someProp, { type: OTHER_ACTION, payload: action.payload.something })
}
default:
return {
...state,
someProp: someOtherReducer(state.someProp)
}
}
}
function mapStateToProps(state) {
const filter = state.something.filter
const items = state.other.items
return {
items: filterItems(items, filter)
}
}
connect(mapStateToProps)(...)
Каждый раз, когда мне нужно вызвать событие с уведомлением (будь то новое уведомление или удаление старого), мне нужно доставать имеющийся массив this.props.layout.notification, модифицировать его и отправлять обратно для перезаписи
dispatch({
type: 'ADD_NOTIFICATION',
payload: { notification: { ... } },
})
// rootEntity reducer
const initialState = {
entities: {}
}
function rootEntityReducer(state = initialState, action = {}) {
switch(action.type) {
case ADD_ELEMENT:
const { targetEntityId, element } = action.payload
const targetEntity = state.entities[targetEntityId]
return {
...state,
entites: {
...state.entities,
[targetEntityId]: { ...targetEntity, elements: [ ...targetEntity.elements, element ] }
}
}
default:
return state
}
}
// rootEntity reducer
const initialState = {
entities: []
}
function rootEntityReducer(state = initialState, action = {}) {
switch(action.type) {
case ADD_ELEMENT:
const { targetEntityId, element } = action.payload
return {
...state,
entites: state.entities.map(
entity => entity.id !== targetEntityId
? entity
: { ...entity , elements: [ ...entity.elements, element ] }
)
}
default:
return state
}
}
<div className="filter-popup" onClick={this.props.onClick}>
....
closeModal() {
this.setState({
modalIsOpen: false
});
this.forceUpdate()
},
<li className="filter-result-item" onClick={this.showPopup}>
...
showPopup() { ... }
closeModal(e) {
e.stopPropagation();
this.setState({
modalIsOpen: false
});
},
functiob action1Creator() {
return (dispatch, getState) => {
fetch(...)
.then(JSON.parse)
.then((response) => dispatch(action2Creator(response)))
;
};
}
function action2Creator(response) {
return { type: 'SOME', data: response.data[12] };
}
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;
}
}
function someActionCreator(someArg) {
return {
type: 'SOME_ACTION_NAME',
newStateData: someArg + 5, // <-- разная логика
};
}
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
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);