I am using Redux Toolkit and have a general-purpose ui-slice
that I use for UI states that I need globally.
In particular I have few components that need to know the current width of the window to conditionally render some content. So I made this reducer:
acknowledgeScreenWidth(state, action) {
state.screenWidth = action.payload.screenWidth;
},
I dispatch against this reducer only in one place, in a layout component, like so:
useEffect(() => {
const updateWidth = () => dispatch(uiActions.acknowledgeScreenWidth({ screenWidth: window.innerWidth }));
updateWidth();
window.addEventListener('resize', updateWidth);
return () => window.removeEventListener('resize', updateWidth);
}, []);
And then in the components where I need the current width I have:
const screenWidth = useSelector(store => store.ui.screenWidth);
const isSmall = screenWidth < 768;
Which works because every time screenWidth
changes, the component rerenders and isSmall
is redeclared.
However the components also have other states and there is no need to redeclare isSmall
every time they rerender. (furthermore, the window width is likely to be always the same from the beginning to the end)
So I wonder if creating a local state:
const screenWidth = useSelector(store => store.ui.screenWidth);
const [isSmall, setIsSmall] = useState(true);
useEffect(() => {
setIsSmall(screenWidth < 768)
}, [screenWidth]);
Or memoizing isSmall
:
const screenWidth = useSelector(store => store.ui.screenWidth);
const isSmall = useMemo(() => screenWidth < 768, [screenWidth]);
Could be a better approach, or is actually an anti-pattern.