我有一个帖子模型,该模型具有用户和评论 通过阅读redux文档,我了解到理想状态已被规范化,并使用如下键:
{
"posts": {
"byId": {
1: {
id: 1,
name: "Post One",
user: [10]
},
2: {
id: 2,
name: "Post Two",
user: [11]
}
},
"allIds": [1, 2]
},
"users": {
"byId": {
10: {username: "User One"},
11: {username: "User Two"}
},
"allIds": [10, 11]
}
}
我认为这是正确的状态。现在的问题是,如果我有一个操作获取所有帖子及其用户,评论...
使用normalizr可以将状态标准化以匹配上面的模型。 当我在postsReducer中收听FETCH_POSTS_SUCCESS时。如何在用户自己的根路径中添加用户?
使用postsReducer将导致
state.posts.users
相反,好的做法是这样
state.users
答案 0 :(得分:1)
幼稚的解决方案:让您的userReducer收听FETCH_POSTS_SUCCESS
,如果帖子列表中有任何用户,请更新其自己的状态。当然,这会污染逻辑,因为FETCH_POST_SUCCESS
不再仅属于postReducer。
我可以建议2种替代解决方案:
一种是,如果您使用任何软件包,例如redux-thunk或redux-saga,则在成功提取帖子时调用次要效果。以下示例适用于redux-thunk
function fetchPosts() {
return function(dispatch) {
return fetchPostsAPICall()
.then((posts) => {
dispatch(fetchPostSuccess, posts)
const users = getUsersFromPosts()
dispatch(massUpdateUsers, users)
})
}
}
第二个正在使用中间件来监听FETCH_POST_SUCCESS
,并在其中处理次要效果。以下示例使用redux-saga.takeEvery
function* handleFetchPostsSuccess({ type, payload }) {
const users = getUsersFromPayload(payload)
yield put({ type: 'MASS_UPDATE_USERS', users })
}
function* watchFetchPosts() {
yield takeEvery(FETCH_POSTS_SUCCESS, handleFetchPostsSuccess)
}
...
const sagaMiddleware = createSagaMiddleware()
const store = createStore(
reducer,
applyMiddleware(sagaMiddleware)
)
sagaMiddleware.run(watchFetchPosts)
答案 1 :(得分:1)
创建单独的异径管并将其组合:
function normalizeData(data, initialValue = [], idKey = 'id') {
return data.reduce(
(accumulator, currentValue) => ({
...accumulator,
[currentValue[idKey]]: currentValue,
}),
{},
);
}
function mapIds(data, initialValue = [], idKey = 'id') {
const ids = data.map(eachData => eachData[idKey]);
return [...initialValue, ids];
}
function posts(state = {}, action) {
switch (action.type) {
case types.FETCH_POSTS_SUCCESS:
return {
byId: normalizeData(action.payload.data, state.byId),
allIds: mapIds(action.payload.data, state.allIds),
};
default:
return state;
}
}
function users(state = {}, action) {
switch (action.type) {
case types.FETCH_USERS_SUCCESS:
return {
byId: normalizeData(action.payload.data, state.byId),
allIds: mapIds(action.payload.data, state.allIds),
};
default:
return state;
}
}
export default combineReducers({ posts, users });
您还可以为这些创建辅助包装器,这些包装器可重复使用以轻松创建其他实体化简器:
const byIdReducerCreator = (actionType, idKey = 'id') => (state = {}, action) => {
switch (action.type) {
case types[actionType]:
return normalizeData(action.payload.data, state, idKey);
default:
return state;
}
};
const allIdReducerCreator = (actionType, idKey = 'id') => (state = [], action) => {
switch (action.type) {
case types[actionType]:
return mapIds(action.payload.data, state, idKey);
default:
return state;
}
};
const posts = combineReducers({
byId: byIdReducerCreator('FETCH_POSTS_SUCCESS'),
allIds: allIdReducerCreator('FETCH_POSTS_SUCCESS'),
});
const users = combineReducers({
byId: byIdReducerCreator('FETCH_USERS_SUCCESS', 'someOtherId'),
allIds: allIdReducerCreator('FETCH_USERS_SUCCESS', 'someOtherId'),
});
export default combineReducers({ posts, users });