【问题标题】:React Hook "useState" can not set full value of array after being filterReact Hook“useState”在过滤后无法设置数组的完整值
【发布时间】:2021-02-01 09:32:42
【问题描述】:

我正在尝试将过滤后的数组值设置为useState的默认值,示例代码如下:

var { studentList } = useContext(StudentListContext);
var selectedWarningStudents = flattenScoreList(studentList).filter((item) => {
    return selected.includes(item._id);
});

debugger

var [mailList, setMailList] = useState(selectedWarningStudents);
console.log('mailList', mailList);

这是设置调试器后打印的内容,如您所见,数组“studentList”有 91 个项目,数组“selectedWarningStudents”有 3 个项目与数组“selected”中的 3 个项目匹配。所以这里没有什么出乎意料的

在获得数组“selectedWarningStudents”后,我想在下面设置的 useState 中将其值设置为默认值

但是当我登录控制台时,它返回一个仅包含数组“selectedWarningStudents”中的第一项的数组,这里:

感谢您花时间帮助我,祝您有美好的一天

【问题讨论】:

  • 您确定学生列表中的 3 个默认学生 items.id 相同吗?
  • 是的,100% 确定

标签: javascript arrays reactjs react-hooks frontend


【解决方案1】:

您很可能通过异步方式获取studentList 数据。因此,由于您要设置状态而不是使用派生状态,因此您的状态无法赶上。不过,在这种情况下,我希望根本看不到任何数据,但您可以试试这个:

const [mailList, setMailList] = React.useState([]);

React.useEffect(() => {
  var selectedWarningStudents = flattenScoreList(studentList).filter((item) => {
    return selected.includes(item._id);
  });
  setMailList(selectedWarningStudents);
}, [studentList, flattenScoreList, selected]);

但是,您可以导出数据并使用它,而不是这样做,也许使用React.useMemo

const selectedWarningStudents = React.useMemo(
  () =>
    flattenScoreList(studentList).filter((item) => {
      return selected.includes(item._id);
    }),
  [studentList, flattenScoreList, selected]
);

在这种情况下,您没有任何mailList 状态,因为您是从上下文数据派生数据。

顺便说一句,我不知道flattenSocreListselected 是从哪里来的,无论如何我都将它们添加到了依赖数组中。根据您的需要进行更改。

这是一个工作示例。如您所见,Students 组件中没有状态,您不需要它。您可以按原样使用studentList,也可以对其进行过滤并使用此过滤后的数据。

const StudentContext = React.createContext();

const studentData = [
  { id: 1, name: "foo", dep: "aaa" },
  { id: 2, name: "bar", dep: "bbb" },
  { id: 3, name: "baz", dep: "ccc" },
  { id: 4, name: "fizz", dep: "aaa" },
  { id: 5, name: "buzz", dep: "ddd" },
];

function studentApi() {
  return new Promise((resolve) => setTimeout(() => resolve(studentData), 1000));
}

function App() {
  const [studentList, setStudentList] = React.useState([]);

  React.useEffect(() => {
    studentApi().then(setStudentList);
  }, []);

  return (
    <StudentContext.Provider value={studentList}>
      <div className="App">
        <Students />
      </div>
    </StudentContext.Provider>
  );
}

function Students() {
  const studentList = React.useContext(StudentContext);
  const filteredStudents = React.useMemo(
    () => studentList.filter((student) => student.dep === "aaa"),
    [studentList]
  );

  return (
    <div>
      {filteredStudents.map((student) => (
        <div key={student.id}>{student.name} at {student.dep}</div>
      ))}
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>


<div id="root" />

【讨论】:

  • 非常感谢,我对 React useMemo 了解不多,但我尝试了你建议的第一个选项,使用 React useEffect 并且效果很好,非常感谢,祝你有美好的一天
  • 通常情况下,将 props 设置为本地状态并不是一个好主意。您可以直接使用它们或派生(如过滤)并使用它们。州无需使用您的数据。因此,没有useMemo,您可以在过滤后使用它们,而无需状态。如果此组件没有任何变化,则使用 useMemo 只是一种更好的派生状态并避免不必要的计算的方法(在您的情况下为 studentList)。
  • 如果我想在 useMemo 中更改状态,如何更新状态
  • 正如我试图在回答中解释的那样,您不需要有状态。您已经从您的上下文中获取数据,因此不必费心将其作为本地状态保留在您的组件中。如果不需要过滤器,我会说“按原样使用”。为什么你需要一个国家?但是,你有一个过滤器,这意味着你想在那里导出一些数据。您可以使用不带useMemo 的过滤器,并在您的组件中再次使用此过滤后的数据。 useMemo 只是防止不必要的过滤部分。例如,不知何故,父级出于不同的原因重新渲染,但 studentList 没有改变。
  • 我已经更新了我的答案并提供了一个工作示例。
猜你喜欢
  • 2021-09-05
  • 2020-07-21
  • 2020-11-23
  • 2021-08-08
  • 1970-01-01
  • 2022-01-02
  • 2021-12-02
  • 2019-05-08
  • 2021-11-13
相关资源
最近更新 更多