如何防止这种无休止的重新渲染反应?

时间:2020-10-28 16:31:26

标签: javascript reactjs use-effect

我正在构建一个React应用,但是我还不太了解使用钩子的问题。

我的数据以以下格式存储在Firestore中:

userlists > key1 > users: [user1, user2, user3]
                 > date_created: date
                 > listname: "Work Colleagues"
          > key2 > users: [user1, user4, user5]
                 > date_created: date
                 > listname: "Badminton Friends"

(其中user1,user2等是保存用户数据的对象)

因此,在EditUserlistPage中,我想用键userlist来检索key1,并渲染一个UserList组件以显示它。然后,UserList组件为每个用户呈现一个单独的UserItem组件

EditUserlistPage如下(key通过道具传递):

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)

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

最后,props.firebase.getListByKey是:

getListByKey = (key) => this.firestore.collection('userlists').doc(key)

我收到错误和警告。

首先,在屏幕上显示的是: Error: Too many re-renders. React limits the number of renders to prevent an infinite loop. 在控制台中,我还可以看到此错误,它说:

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)

如果我注释掉呈现UserList组件的EditUserlistPage中的行,此错误就会消失。

第二,我在控制台收到警告:

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是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

我试图阅读有关Hooks的React文档,并且我收集到useEffect可能会导致无限重新渲染(如果实施不正确的话),但是我不知道如何正确地进行渲染。

2 个答案:

答案 0 :(得分:2)

主要问题是lapply(subset(airquality, Month == 7), mean, na.rm = T) %>% unlist()代码中的setUsers(usersTemp)

每当更改某些局部状态时,组件都会重新渲染。因此,由于您总是在渲染期间重新设置UserList,因此会触发另一个渲染。

您可以使用users并且仅在useEffect更改时更新users

userList

答案 1 :(得分:1)

使用功能组件时,状态更新时,整个功能将再次运行。因此,在UserList组件中,每次渲染时都要更新状态,从而触发一个新的渲染。

为防止这种情况,请使用无依赖项的useEffect。这将导致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