1

This is my initial data

const data = [
  { id: '1', name: '1' },
  { id: '2', name: '1' },
  { id: '3', name: '2' },
]

I want to loop over and:

  • Where it has name 1 add that object to stateOne
  • Where it has name 2 add that object to stateTwo

End goal both states needs to have Array of Objects inside:

  • stateOne needs to look like
[
  { id: '1', name: '1' },
  { id: '2', name: '1' }
]
  • stateTwo needs to look like
[
  { id: '3', name: '2' },
]

This is what i've tried:

const data = [
  { id: '1', name: '1' },
  { id: '2', name: '1' },
  { id: '3', name: '2' },
]

const Testing = () => {
  const [stateOne, setStateOne] = useState([])
  const [stateTwo, setStateTwo] = useState([])

  useEffect(() => {
    data.forEach((e) => {
      if (e.name === '1') {
        console.log('e', e)
        setStateOne((prevSate) => ({ ...prevSate, e }))
      }
      // if (e.name === '2') {
      //   setStateTwo(e)
      // }
    })
  }, [])

  console.log('stateOne', stateOne)
}
4
  • Is data really static and defined outside the Testing component like that? If so, why the useEffect? Commented Feb 17, 2021 at 11:42
  • 1
    Side note: The purpose of filter is to create and return a new array, which it does by creating a new array and either adding entries to it (if your callback returns truthy value) or not. If you don't use the array filter returns, don't use filter. Just loop through the array with a simple loop, or forEach. Commented Feb 17, 2021 at 11:43
  • data coming from API. I just need to place filter them to correct state so then i can render my component properly. I don't wan to use filter twice which is working. So i know i'm doing something wrong in setState Commented Feb 17, 2021 at 11:43
  • Thanks T.J. good point, but that might not solve my issue on passing data to setState correctly. Commented Feb 17, 2021 at 11:44

5 Answers 5

2

I'd prefer sending data as a prop to that component

You can achieve what you need by


const data = [
  { id: '1', name: '1' },
  { id: '2', name: '1' },
  { id: '3', name: '2' },
]

export default function Testing() {

  const [stateOne, setStateOne] = useState([])
  const [stateTwo, setStateTwo] = useState([])

  useEffect(() => {
    setStateOne(data.filter(e => e.name === "1"))
    setStateTwo(data.filter(e => e.name === "2"))    
    console.log('stateOne', stateOne)
    console.log('stateTwo', stateTwo)
  }, [])
}
Sign up to request clarification or add additional context in comments.

Comments

1

setState functions as an assignment. Like you would normally assign a variable. That means if you want to add something to an array, you need to include that array in the assignment.

Something like this:

      if (e.name === '1') {
        console.log('e', e)
        setStateOne([...stateOne, e])
      }
      if (e.name === '2') {
         setStateTwo([...stateTwo, e])
      }

3 Comments

and don't use filter...use forEach
so used forEach and done that but i'm only console.loging last element :( [{"id":"2","name":"1"}]
You might not get the values you expect when logging the updated state, as setting the state is async. This article might help medium.com/@jlangkammer/…
1

If you don't want to use filter twice for whatever reason, You can create temporary array for each one and manipulate them then update each state respectively like so:

  const [stateOne, setStateOne] = useState([]);
  const [stateTwo, setStateTwo] = useState([]);

  useEffect(() => {
    const tempArr1 = [];
    const tempArr2 = [];

    data.forEach((item) => {
      if (item.name === "1") {
        tempArr1.push(item);
      } else if (item.name === "2") {
        tempArr2.push(item);
      }
    });

    setStateOne(tempArr1);
    setStateTwo(tempArr2);
  }, []);

  console.log(stateOne);
  console.log(stateTwo); 

The problem with what you're doing is you're updating the state each time you find a match which will cause a lot of unnecessary re-renders.

2 Comments

yep this one works, i just wished i could avoid using more variables like the temp*
Then the most conscience answer is @aytek's imho.
0

You've said that data comes from some API you're querying. If so, filter the data once you get it. You can do that in a couple of ways.

With two calls to filter:

const Testing = () => {
    const [stateOne, setStateOne] = useState([]);
    const [stateTwo, setStateTwo] = useState([]);

    useEffect(() => {
        let cancelled = false;
        getTheData(data => {
            if (cancelled) {
                return;
            }
            setStateOne(data.filter(({name}) => name === "1"));
            setStateTwo(data.filter(({name}) => name === "2"));
        };
        return () => {
            // So we don't try to set setate on an unmounted component
            cancelled = true;
        };
    }, []);

    // ...use `dataOne` and `dataTwo` here...
};

Or if you don't want to make two passes through the data, a single loop:

const Testing = () => {
    const [stateOne, setStateOne] = useState([]);
    const [stateTwo, setStateTwo] = useState([]);

    useEffect(() => {
        let cancelled = false;
        getTheData(data => {
            if (cancelled) {
                return;
            }
            const stateOne = [];
            const stateTwo = [];
            for (const entry of data) {
                switch (entry.name) {
                    case "1":
                        stateOne.push(entry);
                        break;
                    case "2": // or default if you want all non-1s in `stateTwo`
                        stateTwo.push(entry);
                        break;
                }
            }
            setStateOne(stateOne);
            setStateTwo(stateTwo);
        };
        return () => {
            // So we don't try to set setate on an unmounted component
            cancelled = true;
        };
    }, []);

    // ...use `dataOne` and `dataTwo` here...
};

2 Comments

i like how you using clean up in useEffect, needs to learn these myself and use them more
@Marius - :-) It matters when setting state after an asynchronous operation, since the component can be unmounted in the meantime...
0

const data = [
    { id: "1", name: "1" },
    { id: "2", name: "1" },
    { id: "3", name: "2" }
  ];
  
  const App = () => {
    const newdata = useState(data);
    const [stateOne, setStateOne] = useState([]);
    const [stateTwo, setStateTwo] = useState([]);
  
    const Filter = () => {
      let listOne = [];
      let listTwo = [];
      newdata[0].map((it) => {
        if (it.name === "1"){
          listOne.push(it);
        }
        else if(it.name === "2"){
          listTwo.push(it)
        }
      });
      setStateOne(listOne);
      setStateTwo(listTwo);
    };
  
    useEffect(() => {
      Filter();
    }, []);

    console.log("stateOne", stateOne)
    console.log("stateTwo", stateTwo)

    return (
      // your code
    )
   
  };

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.