我正在使用 redux,每次调用调度时都会调用我的 reducer 函数,但状态没有更新。并且第一个状态和下一个状态之间没有区别。
ArtclesReducer.ts
const defaultState: Articles = {
articles: [{token: "teken", title: "text", featureImageUrl: ""}],
}
export const articlesReducer: Reducer<Articles, any> = (state = defaultState, action: ArticlesActionTypes) => {
let nextState: Articles = {
articles: state.articles,
}
switch (action.type) {
case ADD_ARTICLES :
let allArticles = [...state.articles, ...action.payload]
return {
articles: [{title: "", token: "", featureImageUrl: ""}, {
title: "",
token: "",
featureImageUrl: ""
}, {title: "", token: "", featureImageUrl: ""}, {title: "", token: "", featureImageUrl: ""}]
}
case UPDATE_ARTICLE:
console.log("in update article")
for (let i = 0; i < nextState.articles.length; i++) {
if (nextState.articles[i].token == action.payload.token) {
nextState.articles[i] = action.payload;
break;
}
}
break;
case DELETE_ARTICLE:
console.log("in delete article")
nextState.articles = nextState.articles.filter(value => {
return value.token != action.payload;
})
break;
default:
}
return nextState;
}
如图所示,我返回一个非空状态。
当您看到状态时,它变得相同并且不会更新
答案 0 :(得分:1)
如果您不确定如何在不改变状态的情况下更新状态,您可以使用 Redux Toolkit 避免很多挫折。该工具包使您可以像更改状态一样编写代码(它处理幕后的不变性问题)。
以下是使用 createReducer
实用程序时此 reducer 的外观:
const articlesReducer = createReducer(defaultState, {
[ADD_ARTICLES]: (state, action) => {
// We don't return anything. We just mutate the passed-in draft state.
state.articles.push(action.payload);
},
[UPDATE_ARTICLE]: (state, action) => {
// Find which article we are updating
const index = state.articles.findIndex(
article => article.token === action.payload.token
);
// Replace that index with the new article from the payload
state.articles[index] = action.payload;
},
[DELETE_ARTICLE]: (state, action) => {
// We replace the articles array with a filtered version
state.articles = state.articles.filter(
article => article.token === action.payload
);
}
});
大多数人不直接使用 createReducer
,因为有一个更好的实用程序 createSlice
可以为您创建动作名称和动作创建者函数!
当然,您仍然可以采用“老式”方式来执行此操作。但是您需要确保永远不会改变状态的任何部分,并且每个案例都返回一个完整的状态。
nextState.articles[i] = action.payload
是 actually a mutation 即使 nextState
是一个副本,因为它是一个浅拷贝,所以 articles
属性指向与当前状态相同的数组。>
除非您确信自己知道自己在做什么,否则我不推荐这种方法,但我想提供一个正确的版本来向您展示它是如何完成的。
export const articlesReducer: Reducer<Articles, any> = (state = defaultState, action: ArticlesActionTypes) => {
switch (action.type) {
case ADD_ARTICLES:
return {
...state,
articles: [...state.articles, ...action.payload]
};
case UPDATE_ARTICLE:
return {
...state,
articles: state.articles.map((article) =>
article.token === action.payload.token ? action.payload : article
)
};
case DELETE_ARTICLE:
return {
...state,
articles: state.articles.filter((article) =>
article.token !== action.payload
)
};
default:
return state;
}
};
注意:像您在 most examples 中看到的那样编写 ...state
在技术上是不必要的,因为 articles
是您所在州的唯一属性,因此 ...state
没有其他属性可以复制{1}}。但是,如果您想在将来添加其他属性,无论如何都包含它可能是个好主意。