1

I am using useState which has 2 array imageList and videoList and then in useEffect hook i am using forEach on data then if type is image then push to item to image . But at last i am not getting imagelist or video list of array.

const [list, setDataType] = useState({imageList:[], videoList:[] });
  useEffect (()=>{
    //data is list of array
      dataList.forEach(item =>{

       if(!item.images)  {
         setDataType({...list, imageList:item})
       } 
       else if (item.images[0].type === "video/mp4")
       {
        setDataType({...list, videoList :item})
       }
       else if((item.images[0].type === "images/gpeg")
       {
          setDataType({...list, imageList:item})
       }
      })
  },);

Here type check is working correctly but at last i get last fetch data only which can be videolist or imageList In last i should get list of all imageList whose type is image and same video list whose type is video

2
  • Don't call a setState constantly inside a loop, build your state then set it. Commented Jan 24, 2020 at 17:15
  • Yeah you can extract all the images and videos in two differnt arrays and then make one call to setState to persist it. Its not an efficient solution to be calling setState in a loop as you are doing Commented Jan 24, 2020 at 17:18

4 Answers 4

3

It is not a proper way to call setState in a loop. Below is an attempted solution using array method filter to functionally construct the list.

const [list, setDataType] = useState({ imageList: [], videoList: [] });
useEffect(() => {
    let videos = dataList.filter(item => item.images[0].type === "video/mp4")
    let images = dataList.filter(item => item.images[0].type === "images/gpeg")
    setDataType({imageList: images, videoList: videos})
}, []);


Sign up to request clarification or add additional context in comments.

4 Comments

worked but useEffect goes in infinite loop "index.js:1 Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render
did you add the empty array [] dependency at the end of the useEffect?
@KUMARSUBHAM you could do this also: [dataList]
Yeah That is if you want to re-run the effect each time the datalist array changes. :thumbsup:
0

Ideally you don't want to be calling setState constantly inside your loop. Build the state up and then set it.

Two filters might work for you here..

eg.

const [list, setDataType] = useState({imageList:[], videoList:[] });
  useEffect (()=>{
    //data is list of array
    setDataType({
      videoList: dataList.filter(item => item.images[0].type === 'video/mp4'),
      imageList: dataList.filter(item => item.images[0].type === 'images/gpeg')
    });
  },);

2 Comments

only video list is getting data and also useEffect is doing in infinite loop
Yes, useEffect has no dependency.. for this try -> }, []); Also did you mean image/jpeg ?
0

Don't use the useEffect & useState hooks for data transformation, which is not part of an asynchronous flow.

This case is better handled with useMemo. When the datalist changes, useMemo will produce the list, and if it doesn't change, the memoized value would be used. In addition, it won't cause an infinite loop, because it won't cause a rerender while listening to its own state.

To create list, use a Map that will hold the mime-types and their respective types. Reduce the array of items, and according to the type you get from the Map, push them in the images or videos sub-arrays.

/** external code (not in the hook) **/
const types = new Map([['video/mp4', 'video'], ['images/gpeg', 'image']])

const getListType = ({ type }) => types.has(type) ? 
  `${types.get(type)}List` : null

/** hook code **/
const list = useMemo(() => dataList.reduce((r, item) => {
  const list = getListType(item.images[0])

  is(list) r[list].push(item)

  return r;
}, { imageList:[], videoList:[] }), [dataList])

Comments

0

Avoid set state inside a loop. On each setState, React will re-render the component. So recommended to prepare your state first and then update the state.

const [list, setDataType] = useState({imageList:[], videoList:[] });
  useEffect (() =>{
      let newState = {imageList:[], videoList:[] };
      dataList.forEach(item =>{

            if(!item.images)  {
                newState.imageList.push(item);
            } else if (item.images[0].type === "video/mp4") {
                newState.videoList.push(item);
            } else if((item.images[0].type === "images/gpeg") {
                newState.imageList.push(item);
            }
      });
      setDataType(prevState => {
        return {
            imageList: newState.imageList, 
            videoList: newState.videoList 
        }
     });
},[]);

5 Comments

In this line setDataType( preState => {...preState, imageList:item}) is saying wrong format
it is going in infinite loop as
this can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
thank you sohail it worked .. i saw ur website its awesome ,
Thank you @Kumar

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.