I am just diving deep into react. But the useEffect react hook still got me confused. I know that I can pass dependencies as an array to it to control rendering of the component. I have used props and local state to do and it works.
What's got me still confused is when I pass redux reducer as a dependency, it causes an infinite loop of rendering the component.
// users component
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 function
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));
}
// users reducer
export default function usersReducer(state = [], action) {
switch (action.type) {
case GET_USERS : {
return [...state, action.payload]
}
}
}
From what I understand users starts off as an empty array, then gets filled with data from an API call. So useEffect should fire twice; when the component has just mounted and then when users state changes from the API call. So what's causing the infinite loop?
Remove users
from the useEffect
dependency because you want to fetch users when component mounts not each time the users
is changed.
useEffect(
useDispatch().dispatch(getUsers)
,[]) // Now, it will fetch users ONLY ONCE when component is mounted
Explanation:
// 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])
So, if you do fetch
in Case 2 , it will change users
which will re-trigger the hook which will fetch
the users again which changes the users
and causes the hook to re-trigger ---> This is an infinite loop .
state.users
is getting changed (in this code), as detected by useEffect
, even when values of state.users
are "SAME" (Same values)? Whenever GET_USERS
action is dispatched, reducer returns new state ( {...state, users: action.payload })
, it does so even when value of action.payload
holds same value of users. This is why useEffect
receives new users array. (They do shallow comparison).
Note that, [1, 2,3] is not equal to [1, 2,3]
ie [1, 2,3] === [1, 2,3]
returns false.
If for some reason, you want to return the same redux state, do return state
in the reducer. This is often what we do in default
case of switch
of reducer.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.