简体   繁体   English

使用 setState 反应 Hook useEffect 问题

[英]React Hook useEffect issue with setState

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 .我正在使用具有 2 个数组 imageList 和 videoList 的 useState ,然后在 useEffect 钩子中,我在数据上使用 forEach ,然后如果类型是图像,则将项目推送到图像。 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这里类型检查工作正常,但最后我只得到最后一次获取的数据,它可以是 videolist 或 imageList 最后我应该得到所有类型为 image 的 imageList 和类型为 video 的相同视频列表的列表

It is not a proper way to call setState in a loop.在循环中调用 setState 不是正确的方法。 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})
}, []);


Avoid set state inside a loop.避免在循环内设置状态。 On each setState, React will re-render the component.在每个 setState 上,React 将重新渲染组件。 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 
        }
     });
},[]);

Ideally you don't want to be calling setState constantly inside your loop.理想情况下,您不希望在循环中不断调用 setState。 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')
    });
  },);

Don't use the useEffect & useState hooks for data transformation, which is not part of an asynchronous flow.不要使用useEffectuseState挂钩进行数据转换,这不是异步流的一部分。

This case is better handled with useMemo .使用useMemo可以更好地处理这种情况。 When the datalist changes, useMemo will produce the list , and if it doesn't change, the memoized value would be used.datalist变化, useMemo会产生list ,如果不改变,将要使用的memoized值。 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.要创建list ,请使用一个 Map 来保存 mime-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.减少item的数组,并根据你从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])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM