Реагирующий хук «useState» не может установить полное значение массива после фильтрации

#javascript #arrays #reactjs #react-hooks #frontend

#javascript #массивы #reactjs #реагирующие крючки #интерфейс

Вопрос:

я пытаюсь установить значение массива после фильтрации в качестве значения 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 элемента, совпадающих с 3 элементами в массиве «selected». Так что здесь нет ничего неожиданного

отладчик

после получения массива «selectedWarningStudents» я хочу установить его значение в качестве значения по умолчанию в useState, которое я установил ниже

но когда я захожу в консоль, он возвращает массив, содержащий только первый элемент из массива «selectedWarningStudents», здесь:

только первый элемент

спасибо, что нашли время, чтобы помочь мне, хорошего дня

Комментарии:

1. Вы уверены, что 3 элемента students по умолчанию.ids одинаковы в списке student?

2. Да, уверен на 100%

Ответ №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 состояния, потому что вы извлекаете данные из контекстных данных.

Кстати, я не знаю, откуда берутся flattenSocreList и selected откуда берутся, в любом случае я добавил их в массивы зависимостей. Измените его в соответствии с вашими потребностями.

Вот рабочий пример. Как вы можете видеть, в компоненте нет состояния 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" />  

Комментарии:

1. большое вам спасибо, я мало что знаю о React useMemo, но я попробовал первый вариант, который вы предложили с помощью React useEffect, и он отлично сработал, большое вам спасибо и хорошего дня

2. Обычно установка реквизитов для вашего локального состояния не является хорошей идеей. Вы можете использовать их напрямую или извлекать (как вы фильтруете) и использовать их. Государству не нужно использовать ваши данные. Итак, без useMemo вы можете использовать их после фильтрации, без состояния. Использование useMemo — это просто более удобный способ получения состояния и избежания ненужных вычислений, если для этого компонента ничего не меняется ( studentList в вашем случае).

3. как я могу обновить состояние, если я хочу изменить его в useMemo

4. Как я пытался объяснить в своем ответе, вам не нужно иметь состояние. Вы уже получаете данные из своего контекста, поэтому не утруждайте себя сохранением их в качестве локального состояния в вашем компоненте. Если нет необходимости в фильтре, я бы сказал «использовать его как есть». Зачем вам там состояние? Но у вас есть фильтр, и это означает, что вы хотите получить некоторые данные там. Вы можете использовать фильтр без useMemo него и снова использовать эти отфильтрованные данные в своем компоненте. useMemo просто предотвращает ненужную часть фильтрации. Например, каким-то образом родительские повторные запросы по другой причине, но studentList не меняются.

5. Я обновил свой ответ и привел рабочий пример.