簡體   English   中英

我如何防止這種無休止的重新渲染反應?

[英]How do I prevent this endless re-render in react?

我正在構建一個 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通過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)

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. 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)

如果我注釋掉 EditUserlistPage 中呈現 UserList 組件的行,這個錯誤就會消失。

其次,我在控制台中收到警告:

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 會導致無限重新渲染,但我不知道如何正確執行。

主要問題在於UserList代碼中的setUsers(usersTemp)

每當某些本地狀態發生更改時,組件就會重新渲染。 因此,由於您總是在渲染期間重新設置users ,因此您觸發了另一個渲染。

您可以使用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

當您使用函數式組件時,當您的狀態更新時,您的整個函數將再次運行。 因此,在您的 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM