I have an array that resides in store, let's call it users
and I have a custom hook that retrieves it from store (via useSelector
). Based on this array in the store, I have a local state in my component that I use as the display source of a table. I need to have it separately in local state since I filter the data based on a search functionality.
What I want to do is, every time when the data in the store changes, I want to update the local state as well to reflect those changes (but call the filtering function on top of it before hand).
This however results in an infinity loop since the useEffect
+ setState
cause a redraw which changes the store variable again etc.
const users = useUsers() // uses redux store
const [displayUsers, setDisplayUsers] = useState(users) // local state
useEffect(() => {
const filteredUsers = onSearch(users) // applies the filtering
setDisplayUsers(filteredUsers) // updates the local state
}, [users])
return <Table source={displayUsers} ... />
Can anybody help?
Since displayUsers
is derived from the props, you don't need to maintain it in the state. Calculate it on the fly whenever the props changes, and use memo if the component is rendered often for other reasons:
const users = useUsers() // uses redux store
const displayUsers = useMemo(() => onSearch(users), [onSearch, users])
return <Table source={displayUsers} ... />
If you really need to set the state when the store changes, make sure that the selector is memoized - ie if nothing changes you'll get the same array. So when re-rendering the component, the selector would return the same users
array, and this will prevent the useEffect
from being called again.
You can call useSelector
with the equalityFn
(2nd param) to avoid returning a new value if nothing changed (see Equality Comparisons and Updates). This is the example from the docs:
import { shallowEqual, useSelector } from 'react-redux'
const selectedData = useSelector(selectorReturningObject, shallowEqual)