React 的 useState 问题,太多的重新渲染
Problem with useState from React, too many re-render
我正在将 fullcalendar 库用于一个小的笔记项目 'to do',只是为了学习 React js(我是新手)。当我从 firebase 上的实时数据库中获取数据时,我尝试在日历中显示事件名称 (evento) 和日期 (fecha),但是当我使用 setName() 来放置数据并将其保存到数组中时name=[]
,然后通过我重新渲染之类的错误,我不知道如何解决....如果有人能帮助我,那就太好了!!
(抱歉我的英语不好)
谢谢
这是错误和代码:
enter image description here
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()
时,组件都是 re-rendered (这是 React 返回的一个特殊函数,用于更改组件状态和 re-render).当它 re-renders 时,再次调用 setName()
,从而导致 re-rendering 中的无限循环。
useEffect()
不是re-render中的运行,而是运行只有在检测到数据发生变化时才会出现。在这种情况下,它会检查 firebase.database().ref().on('value')
是否已更改,如果是,运行 useEffect()
和 re-render.
中的代码
更多可以阅读here。
顺便说一句,可以应用一个小的优化是使用局部变量来存储过程中的值。然后只调用 setName()
一次。因为如前所述,每次调用这个特殊函数时,它
可能会导致 re-render。所以你只想在完成所有中间过程后调用它一次。或者更好的是,以函数式风格进行:
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'));
您有 2 个问题:
- firebase 在 react 组件中创建监听器。
- 在
Array.prototype.forEach
中调用 setName;
我会告诉你循环在哪里。
- 组件已渲染;
- 组件创建状态
[name, setName]
;
- 组件调用
firebase.database().ref().on('value', callback)
;
- Callback 从 firebase 获取数据并通过 forEach 按键迭代;
- 在 forEach 的第一次迭代中调用
setName
;
setName
呼叫 re-render;
- 转到
3
步;
解法:
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}
/>
);
}
我正在将 fullcalendar 库用于一个小的笔记项目 'to do',只是为了学习 React js(我是新手)。当我从 firebase 上的实时数据库中获取数据时,我尝试在日历中显示事件名称 (evento) 和日期 (fecha),但是当我使用 setName() 来放置数据并将其保存到数组中时name=[]
,然后通过我重新渲染之类的错误,我不知道如何解决....如果有人能帮助我,那就太好了!!
(抱歉我的英语不好)
谢谢
这是错误和代码:
enter image description here
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()
时,组件都是 re-rendered (这是 React 返回的一个特殊函数,用于更改组件状态和 re-render).当它 re-renders 时,再次调用 setName()
,从而导致 re-rendering 中的无限循环。
useEffect()
不是re-render中的运行,而是运行只有在检测到数据发生变化时才会出现。在这种情况下,它会检查 firebase.database().ref().on('value')
是否已更改,如果是,运行 useEffect()
和 re-render.
更多可以阅读here。
顺便说一句,可以应用一个小的优化是使用局部变量来存储过程中的值。然后只调用 setName()
一次。因为如前所述,每次调用这个特殊函数时,它
可能会导致 re-render。所以你只想在完成所有中间过程后调用它一次。或者更好的是,以函数式风格进行:
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'));
您有 2 个问题:
- firebase 在 react 组件中创建监听器。
- 在
Array.prototype.forEach
中调用 setName;
我会告诉你循环在哪里。
- 组件已渲染;
- 组件创建状态
[name, setName]
; - 组件调用
firebase.database().ref().on('value', callback)
; - Callback 从 firebase 获取数据并通过 forEach 按键迭代;
- 在 forEach 的第一次迭代中调用
setName
; setName
呼叫 re-render;- 转到
3
步;
解法:
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}
/>
);
}