Tam Do
Tam Do

Reputation: 321

React Hook "useState" can not set full value of array after being filter

i am trying to set value of an array after being filter as the default value of useState, here is the sample code:

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);

this is what it printed after set debugger, as you can see, array "studentList" has 91 items, array "selectedWarningStudents" has 3 items match with 3 item in the array "selected". So nothing is unexpected here

debugger

after get the array "selectedWarningStudents" i want to set its value as default value in the useState that i set below

but when i log the console it return an array that contains only first item from array "selectedWarningStudents", here:

first item only

thank you for taking time to help me out, have a good day

Upvotes: 0

Views: 889

Answers (1)

devserkan
devserkan

Reputation: 17608

Most probably you are getting the studentList data via an async way. So, since you want to set a state instead of using a derived state, your state can't catch up. Though, in this case, I expect to see no data at all but you can try this:

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

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

But, instead of doing this you can derive the data and use it, maybe with React.useMemo

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

In this case, you don't have any mailList state, because you are deriving the data from Context data.

By the way, I don't know where do flattenSocreList and selected come from, in any case I added them into the dependency arrays. Change it according to your needs.

Here is a working example. As you can see, there is no state in Students component, you don't need it. You can use studentList as it is or you can filter it and use this filtered data.

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" />

Upvotes: 1

Related Questions