编辑:
我解决了减速器的问题。。。更改为:
case ADD_LIST_ITEM:
return {
...state,
lists: {
...state.lists.map(list =>
list._id === payload.id
? { ...list, listItems: payload.data }
: list
)
},
loading: false
};
到此:
case ADD_LIST_ITEM:
return {
...state,
lists: [
...state.lists.map(list =>
list._id === payload.id
? { ...list, listItems: payload.data }
: list
)
],
loading: false
};
我犯了一个愚蠢的错误。
我有一个MERN todo应用程序,它使用redux进行状态管理,并使用useEffect()进行UI更新(所有功能组件而不是基于类的组件)。但是,当我在redux存储中更改状态时,UI不会更新。这似乎只发生在由从前端到后端的post请求触发的更新期间,在该更新中,我将数据传递给一个操作,该操作在reducer(一个js文件,而不是该应用程序中的useReducer()钩子)中处理。我的后端会正常更新,但UI会崩溃。
发生的情况是,我在给定的待办事项列表中输入一个新的列表项,得到的错误是:
Uncaught TypeError: list.lists.map is not a function
at Dashboard (Dashboard.jsx:32)
如果需要,或者我的减速器有问题,我不确定在哪里使用额外的useEffect()。。。以下是相关的流程(删除了所有className声明和不相关的部分):
/* Dashboard.jsx */
// imports //
const Dashboard = ({ auth: { user }, list, getLists }) => {
useEffect(() => {
getLists();
}, [getLists]);
return (
<>
<p>Lists...</p>
{list.lists &&
list.lists.map(list => <List key={list._id} list={list} />)}
</>
);
};
Dashboard.propTypes = {
getLists: PropTypes.func.isRequired,
list: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
list: state.list
});
export default connect(mapStateToProps, { getLists })(Dashboard);
/* List.jsx */
// imports
const List = ({ list, addListItem, getLists }) => {
const [text, setText] = useState('');
useEffect(() => {
getLists();
}, []);
const handleAddItem = e => {
e.preventDefault();
addListItem(list._id, { text });
setText('');
};
return (
<div>
{list.listItems &&
list.listItems.map((item, index) => (
<ListItem
key={index}
item={item}
listId={list._id}
itemIndex={index}
/>
))}
<div>
<form onSubmit={handleAddItem}>
<input
type="text"
name="text"
placeholder="add a to-do item"
value={text}
onChange={e => setText(e.target.value)}
/>
<input type="submit" value="add" />
</form>
</div>
</div>
);
};
List.propTypes = {
addListItem: PropTypes.func.isRequired,
getLists: PropTypes.func.isRequired
};
export default connect(null, {
addListItem,
getLists
})(List);
/* list.actions.js */
// imports
export const addListItem = (listId, text) => async dispatch => {
try {
const res = await api.post(`/lists/${listId}`, text); // returns all list items after adding new item
dispatch({
type: ADD_LIST_ITEM,
payload: { id: listId, data: res.data }
});
} catch (err) {
dispatch({
type: LIST_ERROR,
payload: { message: err.response.statusText, status: err.response.status }
});
}
};
/* list.reducer.js */
// imports
const initialState = {
lists: [],
list: null,
loading: true,
error: {}
};
const list = (state = initialState, action) => {
const { type, payload } = action;
switch (type) {
case GET_LISTS:
return { ...state, lists: payload, loading: false };
case LIST_ERROR:
return { ...state, error: payload, loading: false };
case ADD_LIST_ITEM:
return {
...state,
lists: {
...state.lists.map(list =>
list._id === payload.id
? { ...list, listItems: payload.data }
: list
)
},
loading: false
};
default:
return state;
}
};
export default list;
我假设在创建应用程序商店时,您将list
作为rootReducer、传递
这意味着您的应用程序的主状态正是list
正在管理的状态。
因此,如果您需要访问状态的属性lists
,您需要这样做:
const mapStateToProps = state => ({
lists: state.lists /// state in here is exactly the state of list reducer
});
现在,在Dashboard
中,lists
是您在list
reducer中操作的数组。
此外,您还在list
reducer中定义了一个名为list
的特性。它最初被定义为null,同样在reducer中,您永远不会更改它:
const initialState = {
lists: [],
list: null, /// none of actions ever change this, meaning it's currently useless.
loading: true,
error: {}
};