我只是在深入研究 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 调用中改变时。那么是什么导致了无限循环?
答案 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
情况下所做的。