[英]How do I prevent this endless re-render in react?
I'm building a React app, but I haven't quite got my head around the use of hooks yet.我正在构建一个 React 应用程序,但我还没有完全了解钩子的使用。
My data is stored in the following format in Firestore:我的数据以以下格式存储在 Firestore 中:
userlists > key1 > users: [user1, user2, user3]
> date_created: date
> listname: "Work Colleagues"
> key2 > users: [user1, user4, user5]
> date_created: date
> listname: "Badminton Friends"
(where user1, user2 etc are objects holding user data) (其中 user1、user2 等是保存用户数据的对象)
So, in EditUserlistPage
I want to retrieve the userlist
with key key1
, and render a UserList
component to show it.所以,在
EditUserlistPage
我要检索的userlist
与主要key1
,并呈现UserList
组件来证明这一点。 The UserList
component then renders an individual UserItem
component for each user UserList
组件然后为每个用户呈现一个单独的UserItem
组件
EditUserlistPage
is as follows ( key
is passed in via props): EditUserlistPage
如下( key
通过props传入):
const EditUserlistPage = (props) => {
// Get list key
const listKey = props.key
// Set up state variables
const [userlist, setUserlist] = useState({})
// Load list from db once component has mounted
useEffect(() => {
props.firebase.getListByKey(listKey).get().then(doc => {
let userlist = doc.data()
setUserList(userList)
})
}, [listKey, props.firebase])
return (
<div>
<h1>Edit User List</h1>
<UserList
userlist={userList}
/>
</div>
)
}
export default withFirebase(EditUserlistPage)
The UserList
component is: UserList
组件是:
const UserList = (props) => {
// Get list
const { userlist } = props
// Set up state variable - users
const [ users, setUsers] = useState([])
// Now get all users as objects
let usersTemp = []
for(let ii=0; ii<userlist.users.count; ii++) {
const user = userlist.users[ii]
const userItem = {
id: user.index,
name: user.firstname + user.surname
... // More things go here, but I don't think they're relevant
}
usersTemp.push(userItem)
}
}
setUsers(usersTemp)
return (
<div className="userList">
{ // This will render a UserItem component}
</div>
)
}
export default UserList
Finally, props.firebase.getListByKey
is:最后,
props.firebase.getListByKey
是:
getListByKey = (key) => this.firestore.collection('userlists').doc(key)
I'm getting an error and a warning.我收到错误和警告。
Firstly, displayed on screen is: Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.
首先,屏幕上显示的是:
Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.
Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.
In the console I can also see this error, and it says:在控制台中,我也可以看到这个错误,它说:
The above error occurred in the <UserList> component:
in UserList (at EditUserlistPage/index.js:59)
in div (at EditUserlistPage/index.js:54)
in EditUserlistPage (at context.js:7)
This error goes away if I comment out the line in EditUserlistPage which renders the UserList component.如果我注释掉 EditUserlistPage 中呈现 UserList 组件的行,这个错误就会消失。
Secondly, I'm getting a warning in the console:其次,我在控制台中收到警告:
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
in EditUserlistPage (at context.js:7)
context.js is the Firebase Context, and is: context.js 是 Firebase 上下文,并且是:
const FirebaseContext = React.createContext(null)
export const withFirebase = Component => props => (
<FirebaseContext.Consumer>
{firebase => <Component {...props} firebase={firebase} />} // Line 7
</FirebaseContext.Consumer>
)
export default FirebaseContext
I've tried to read the React documentation on Hooks, and I've gathered that useEffect can caused infinite re-rendering if not implemented properly, but I can't figure out how to do it correctly.我尝试阅读有关 Hooks 的 React 文档,并且我发现如果未正确实现 useEffect 会导致无限重新渲染,但我不知道如何正确执行。
The main problem is with setUsers(usersTemp)
in the code of the UserList
.主要问题在于
UserList
代码中的setUsers(usersTemp)
。
Whenever some local state is changed, the component re-renders.每当某些本地状态发生更改时,组件就会重新渲染。 So, since you always re-set the
users
during the render, you trigger another render.因此,由于您总是在渲染期间重新设置
users
,因此您触发了另一个渲染。
You could use a useEffect
and only update the users
when the userList
changes您可以使用
useEffect
并仅在userList
更改时更新users
const UserList = (props) => {
// Get list
const {
userlist
} = props
// Set up state variable - users
const [users, setUsers] = useState([])
useEffect(() => {
// Now get all users as objects
let usersTemp = []
for (let ii = 0; ii < userlist.users.count; ii++) {
const user = userlist.users[ii];
const userItem = {
id: user.index,
name: user.firstname + user.surname
... // More things go here, but I don't think they're relevant
}
usersTemp.push(userItem)
}
}
setUsers(usersTemp)
}, [userlist])
return (
<div className="userList">
{ // This will render a UserItem component}
</div>
)
}
export default UserList
When you're using functional components, your entire function will run again when your state updates.当您使用函数式组件时,当您的状态更新时,您的整个函数将再次运行。 So in your UserList component, you're updating the state every time it renders, therefore triggering a new render.
因此,在您的 UserList 组件中,每次渲染时都会更新状态,从而触发新的渲染。
To prevent that, use useEffect with no dependencies.为了防止这种情况,请使用没有依赖项的 useEffect。 That will cause the useEffect to only run once when the component mounts, very much like a componentDidMount.
这将导致 useEffect 在组件挂载时只运行一次,非常类似于 componentDidMount。
const UserList = (props) => {
// Get list
const { userlist } = props
// Set up state variable - users
const [ users, setUsers] = useState([])
useEffect(() => {
// Now get all users as objects
let usersTemp = []
for(let ii=0; ii<userlist.users.count; ii++) {
const user = userlist.users[ii]
const userItem = {
id: user.index,
name: user.firstname + user.surname
... // More things go here, but I don't think they're relevant
}
usersTemp.push(userItem)
}
}
setUsers(usersTemp)
},[])
return (
<div className="userList">
{ // This will render a UserItem component}
</div>
)
}
export default UserList
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.