反应状态更新问题
React State Updation Issue
我的组件状态如下:
const [state, setState] = useState({
teamMembersOptions: [],
selectedTeamMember: {},
});
teamMembersOptions 从 redux state teamMembersList 映射如下:
const teamMembersList = useSelector(state => state.get_all_team_members.team)
useEffect(() => {
if (teamMembersList)
mapTeamMembers();
}, [teamMembersList])
const mapTeamMembers = () => {
const teamMembers = [];
teamMembersList.map(member => {
const memberObject = {
'value': member.id,
'label': member.first_name.charAt(0).toUpperCase() + member.first_name.slice(1) + ' ' + member.last_name.charAt(0).toUpperCase() + member.last_name.slice(1)
}
if (member.is_leader == 1) {
memberObject.label = memberObject.label + ' (owner)'
setState({
...state,
selectedTeamMember: memberObject
})
}
teamMembers.push(memberObject)
})
setState({
...state,
teamMembersOptions: teamMembers
})
}
selectedTeamMember 和teamMemberOptions 的状态变量没有更新,一直安慰空状态。每当我在 mapTeamMembers 函数中控制 teamMembers 的本地数组时,它都会成功记录来自 Redux 的所有值 teamMembersList
也成功记录,这意味着 teamMembersList 和 teamMembers 不为空。但是状态没有更新。为什么 mapTeamMembers 函数中的 setState 语句没有更新状态?
这里发生了很多事情,其中很多会导致渲染触发更多渲染,这就是为什么您会得到意外输出的原因。
我分别在数据和计算方法周围添加了useMemo()
和useCallback()
,并将它们的return值添加到useEffect()
的依赖数组中。这是为了避免 useEffect
依赖项在每次渲染时发生变化。
在 .map()
函数中调用 setState()
感觉也不是正确的选择,因为每次调用它时都可能会发生渲染,即使您已经进行了一半的映射操作。相反,我建议并选择在数组上使用 .reduce()
并 returning 该结果,然后可用于更新 useEffect
挂钩中的状态。
查看下面的工作代码和给定来自 teamMembersList
的定义输入的示例输出。注意:这在示例中没有使用 Redux,因为它更多的设置是为了证明这个概念。
import { useCallback, useEffect, useMemo, useState } from "react";
export default function App() {
const [state, setState] = useState({
teamMembersOptions: [],
selectedTeamMember: {}
});
const teamMembersList = useMemo(
() => [
{ id: 1, first_name: "John", last_name: "Smith", is_leader: 0 },
{ id: 2, first_name: "Maggie", last_name: "Simpson", is_leader: 1 }
],
[]
);
const mapTeamMembers = useCallback(
() =>
teamMembersList.reduce(
(acc, member) => {
const memberObject = {
value: member.id,
label:
member.first_name.charAt(0).toUpperCase() +
member.first_name.slice(1) +
" " +
member.last_name.charAt(0).toUpperCase() +
member.last_name.slice(1)
};
if (member.is_leader === 1) {
memberObject.label = memberObject.label + " (owner)";
acc.leader = memberObject;
}
acc.teamMembers.push(memberObject);
return acc;
},
{
teamMembers: [],
leader: ""
}
),
[teamMembersList]
);
useEffect(() => {
if (teamMembersList) {
const members = mapTeamMembers();
setState({
selectedTeamMember: members.leader,
teamMembersOptions: members.teamMembers
});
}
}, [teamMembersList, mapTeamMembers, setState]);
return (
<div>
<pre>
<code>{JSON.stringify(state, null, 4)}</code>
</pre>
</div>
);
}
以上将呈现:
{
"selectedTeamMember": {
"value": 2,
"label": "Maggie Simpson (owner)"
},
"teamMembersOptions": [
{
"value": 1,
"label": "John Smith"
},
{
"value": 2,
"label": "Maggie Simpson (owner)"
}
]
}
我会考虑将 state
对象拆分为单独的状态项,但这完全取决于您以及您希望如何处理数据。
我的组件状态如下:
const [state, setState] = useState({
teamMembersOptions: [],
selectedTeamMember: {},
});
teamMembersOptions 从 redux state teamMembersList 映射如下:
const teamMembersList = useSelector(state => state.get_all_team_members.team)
useEffect(() => {
if (teamMembersList)
mapTeamMembers();
}, [teamMembersList])
const mapTeamMembers = () => {
const teamMembers = [];
teamMembersList.map(member => {
const memberObject = {
'value': member.id,
'label': member.first_name.charAt(0).toUpperCase() + member.first_name.slice(1) + ' ' + member.last_name.charAt(0).toUpperCase() + member.last_name.slice(1)
}
if (member.is_leader == 1) {
memberObject.label = memberObject.label + ' (owner)'
setState({
...state,
selectedTeamMember: memberObject
})
}
teamMembers.push(memberObject)
})
setState({
...state,
teamMembersOptions: teamMembers
})
}
selectedTeamMember 和teamMemberOptions 的状态变量没有更新,一直安慰空状态。每当我在 mapTeamMembers 函数中控制 teamMembers 的本地数组时,它都会成功记录来自 Redux 的所有值 teamMembersList 也成功记录,这意味着 teamMembersList 和 teamMembers 不为空。但是状态没有更新。为什么 mapTeamMembers 函数中的 setState 语句没有更新状态?
这里发生了很多事情,其中很多会导致渲染触发更多渲染,这就是为什么您会得到意外输出的原因。
我分别在数据和计算方法周围添加了useMemo()
和useCallback()
,并将它们的return值添加到useEffect()
的依赖数组中。这是为了避免 useEffect
依赖项在每次渲染时发生变化。
在 .map()
函数中调用 setState()
感觉也不是正确的选择,因为每次调用它时都可能会发生渲染,即使您已经进行了一半的映射操作。相反,我建议并选择在数组上使用 .reduce()
并 returning 该结果,然后可用于更新 useEffect
挂钩中的状态。
查看下面的工作代码和给定来自 teamMembersList
的定义输入的示例输出。注意:这在示例中没有使用 Redux,因为它更多的设置是为了证明这个概念。
import { useCallback, useEffect, useMemo, useState } from "react";
export default function App() {
const [state, setState] = useState({
teamMembersOptions: [],
selectedTeamMember: {}
});
const teamMembersList = useMemo(
() => [
{ id: 1, first_name: "John", last_name: "Smith", is_leader: 0 },
{ id: 2, first_name: "Maggie", last_name: "Simpson", is_leader: 1 }
],
[]
);
const mapTeamMembers = useCallback(
() =>
teamMembersList.reduce(
(acc, member) => {
const memberObject = {
value: member.id,
label:
member.first_name.charAt(0).toUpperCase() +
member.first_name.slice(1) +
" " +
member.last_name.charAt(0).toUpperCase() +
member.last_name.slice(1)
};
if (member.is_leader === 1) {
memberObject.label = memberObject.label + " (owner)";
acc.leader = memberObject;
}
acc.teamMembers.push(memberObject);
return acc;
},
{
teamMembers: [],
leader: ""
}
),
[teamMembersList]
);
useEffect(() => {
if (teamMembersList) {
const members = mapTeamMembers();
setState({
selectedTeamMember: members.leader,
teamMembersOptions: members.teamMembers
});
}
}, [teamMembersList, mapTeamMembers, setState]);
return (
<div>
<pre>
<code>{JSON.stringify(state, null, 4)}</code>
</pre>
</div>
);
}
以上将呈现:
{
"selectedTeamMember": {
"value": 2,
"label": "Maggie Simpson (owner)"
},
"teamMembersOptions": [
{
"value": 1,
"label": "John Smith"
},
{
"value": 2,
"label": "Maggie Simpson (owner)"
}
]
}
我会考虑将 state
对象拆分为单独的状态项,但这完全取决于您以及您希望如何处理数据。