React redux reducer 作为 UseEffect 依赖导致无限循环

时间:2021-02-27 22:28:40

标签: javascript reactjs redux

我只是在深入研究 React。但是 useEffect 反应钩子仍然让我感到困惑。我知道我可以将依赖项作为数组传递给它来控制组件的渲染。我使用了 props 和 local state 来做并且它有效。

让我仍然困惑的是,当我将 redux reducer 作为依赖项传递时,它会导致渲染组件的无限循环。

// 用户组件

const usersComp = () => {
const users = useSelector(state => state.users); 

useEffect(
    // fetch users and update users state
    useDispatch().dispatch(getUsers)
,[users]) // <-- causes an infinite loop!! 

if(users.length){
    return( users.map(user => <p>{user}</p>))
}

}

// getUsers Redux Thunk 函数

export async function getUsers(dispatch, getState) {
fetch(endpoint)
    .then(response => response.json())
    .then(users => {
        dispatch({type: GET_USERS, payload: users})
    }).catch(err => console.error("Error: ", err));

}

// 用户减速器

  export default function usersReducer(state = [], action) {
     switch (action.type) {

        case GET_USERS : {
            return [...state, action.payload]
        }
    }
}

据我所知,用户从一个空数组开始,然后填充来自 API 调用的数据。所以 useEffect 应该触发两次;当组件刚刚安装,然后当用户状态从 API 调用中改变时。那么是什么导致了无限循环?

1 个答案:

答案 0 :(得分:3)

users 依赖项中删除 useEffect,因为您希望在组件安装时获取用户,而不是每次更改 users

useEffect(
    useDispatch().dispatch(getUsers)
,[]) // Now, it will fetch users ONLY ONCE when component is mounted

说明:

// Case 1
useEffect(() => {
  console.log("Mounted") // printed only once when component is mounted
}, [])

// Case 2
useEffect(() => {
  console.log("users changed") // printed each time when users is changed
}, [users])

因此,如果您在 Case 2 中执行 fetch,它会改变 users 这将重新触发将 {{ 1}} 用户再次更改 fetch 并导致钩子重新触发 ---> 这是一个无限循环

更新:

为什么 users 会被更改(在此代码中),由 state.users 检测到,即使 useEffect 的值是“SAME”(相同值)?

每当 state.users 操作被分派时,reducer 返回 new 状态(GET_USERS,即使 { ...state, users: action.payload }) 的值与用户的值相同,它也会这样做。 这就是 action.payload 接收 new users 数组的原因。 (他们做浅层比较)。

请注意,useEffect[1, 2,3] is not equal to [1, 2,3] 返回 false。

如果出于某种原因,您想返回 same redux 状态,请在 reducer 中执行 [1, 2,3] === [1, 2,3]。这通常是我们在 return state 的 reducer 的 default 情况下所做的。