React的useState出现问题,重新渲染过多



我正在使用fullcalendar库来完成一个小项目,只为学习React js(我是新手(。当我从firebase上的实时数据库中获取数据时,我会尝试在日历中显示事件的名称(evento(和日期(fecha(,但当我使用setName((将数据放入数组name=[]时,会出现一个错误,比如重新渲染,我不知道如何修复它……如果有人能帮助我,那就太好了!!

(很抱歉我英语不好(

感谢

这是错误和代码:

在此处输入图像描述

    const [date, SetFecha] = useContext(Contexto)
    const [name, setName] = useState([])
    firebase.database().ref().on('value', (snapshot) => {
        let obj = snapshot.val()
        Object.values(obj.Notas).forEach(e => {
            setName([...name, { title: e.evento, date: e.fecha }])
        });
    })

    const DateClick = (arg) => {
        SetFecha(arg.dateStr)    
    }
    return (
        <FullCalendar
            plugins={[dayGridPlugin, listPlugin, interactionPlugin]}
            initialView="dayGridMonth"
            dateClick={DateClick}
            events={name} 
        />
    )

解决方案

 useEffect(() => {
        firebase.database().ref().on('value', (snapshot) => {
            let obj = snapshot.val()
            let arr = []
            Object.values(obj.Notas).forEach(e => {
                arr.push({ title: e.evento, date: e.fecha })
            });
            setName(arr)
        })
    }, []);

您想要使用useEffect挂钩。试试类似的东西:

  useEffect(() => {
    firebase.database().ref().on('value', (snapshot) => {
      const obj = snapshot.val();
      const arrData = [];
      Object.values(obj.Notas).forEach(e => 
        arrData.push({ title: e.evento, date: e.fecha }));
      setName(arrData);
    });
  }, firebase.database().ref().on('value'));

上面显示的代码中的问题是,每次调用setName()时,都会重新渲染组件(这是React返回的一个特殊函数,用于更改组件状态并重新渲染(。当它重新渲染时,setName()会被再次调用,从而在重新渲染中产生无限循环。

useEffect()不会在重新渲染中运行,而是仅在检测到数据已更改时运行。在这种情况下,它会检查firebase.database().ref().on('value')是否已更改,如果是,则在useEffect()中运行代码并重新渲染。

更多内容可以在这里阅读。

顺便说一句,有一个小的优化可以应用是使用一个局部变量来存储过程中的值。然后只调用setName()一次。因为如前所述,每次调用这个特殊函数时可能导致重新渲染。因此,当您完成所有中间过程时,您只想调用它一次。或者更好的是,以一种功能性的方式进行:

  useEffect(() => {
    firebase.database().ref().on('value', (snapshot) => {
      setName(Object.values(snapshot.val().Notas).map(e => 
        { title: e.evento, date: e.fecha }));
    });
  }, firebase.database().ref().on('value'));

您有两个问题:

  1. firebase在react组件内部创建监听器
  2. 调用Array.prototype.forEach内部的setName

我会告诉你循环在哪里。

  1. 渲染组件
  2. 组件创建状态[name, setName]
  3. 组件调用firebase.database().ref().on('value', callback)
  4. 回调从firebase获取数据,并通过forEach按键进行迭代
  5. 在forEach内部的第一次迭代中,您调用setName
  6. setName调用重新渲染
  7. 进入CCD_ 14步骤

解决方案:

function OwnComponent(props) {
  const [date, setFecha] = useContext(Contexto);
  const [name, setName] = useState([]);
    
  const dateClick = React.useCallback((arg) => {
    setFecha(arg.dateStr);
  }, [setFecha]);
    
  React.useEffect(() => {
    const unsubscribe = firebase.database().ref(/* you can pass 'Notas' 
 here */).on('value', (snapshot) => {
      setName(Object.values(snapshot.val().Notas/* you can remove .Notas here */).map(
        ({ evento: title, fecha: date }) => ({ title, date })
      ));
    });
    return () => {
      unsubscribe();
    };
  }, []);
    
  return (
    <FullCalendar
      plugins={[dayGridPlugin, listPlugin, interactionPlugin]}
      initialView="dayGridMonth"
      dateClick={dateClick}
      events={name} 
    />
  );
}

相关内容

  • 没有找到相关文章

最新更新