使用setState反应Hook useEffect问题

时间:2020-01-24 17:09:27

标签: javascript reactjs ecmascript-6 react-hooks

我正在使用useState,它具有2个数组imageList和videoList,然后在useEffect挂钩中,我在数据上使用forEach,然后如果type为image,则将项目推到image。 但是最后我没有得到数组的图像列表或视频列表。

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

这里的类型检查正常工作,但最后我只获取了最后一个数据,可以是videolist或imageList 最后,我应该获取所有类型为图像的imageList和相同类型为video的相同视频列表的列表

4 个答案:

答案 0 :(得分:3)

这不是在循环中调用setState的正确方法。以下是尝试使用数组方法过滤器从功能上构造列表的解决方案。

Foreach ADO Enumerator

答案 1 :(得分:0)

避免在循环内设置状态。在每个setState上,React将重新渲染组件。因此建议先准备您的状态,然后再更新状态。

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 
        }
     });
},[]);

答案 2 :(得分:0)

理想情况下,您不想在循环内不断调用setState。建立状态,然后进行设置。

在这里两个过滤器可能对您有用。

例如

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')
    });
  },);

答案 3 :(得分:0)

请勿使用useEffectuseState钩子进行数据转换,这不是异步流的一部分。

使用useMemo可以更好地处理这种情况。当datalist发生变化时,useMemo将产生list,如果不发生变化,将使用记忆值。此外,它不会导致无限循环,因为在侦听其自身状态时不会引起重新渲染。

要创建list,请使用可容纳mime类型及其各自类型的Map。减少项目的数组,并根据您从Map中获得的类型,将它们推入imagesvideos子数组中。

/** 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])