反应状态更新问题

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 对象拆分为单独的状态项,但这完全取决于您以及您希望如何处理数据。