Asked 1 month ago by JovianGuardian869
Why isn’t useEffect triggered when Redux state updates via useSelector?
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
Asked 1 month ago by JovianGuardian869
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
I have a simple Tile component that should change color on hover by updating a Redux state. On hover, I dispatch an action with dispatch(setSelectedTile(props.id)). I then use a useEffect hook with a dependency on the Redux state (acquired using useSelector) to perform side effects (logging in this case).
Although the Redux state updates as seen in Redux DevTools, the useEffect function is never triggered. I also tried logging the state with store.getState(), but it always returns the initial state. Can someone help me understand what might be causing this issue?
Below is my Tile component code:
JAVASCRIPTimport React, { useEffect } from 'react'; import { useDispatch, useSelector, } from 'react-redux'; import { setSelectedTile } from './app/slices/tileSlice'; import Player from './Player'; const baseTileStyles = { backgroundColor: "lightgray", transition: "ease 500ms background-color", display: "flex", alignItems: "center", justifyContent: "center", height: "100%", width: "100%" }; const selectedStyles = { ...baseTileStyles, backgroundColor: "gray" }; const getTileStyle = isSelected => { return isSelected ? selectedStyles : baseTileStyles; }; export const Tile = (props) => { const dispatch = useDispatch() let tilestate = useSelector(state => state.selectedTile) useEffect(() => { console.log('selectedTile updated %d', tilestate) }, [tilestate]) return ( <div onMouseEnter={() => dispatch(setSelectedTile(props.id))} style={getTileStyle(tilestate === props.id)}> <Player streamUrl={props.streamUrl} isSelected={props.isSelected} /> </div> ) } export default Tile;
Tile state reducer:
JAVASCRIPTimport { createSlice } from '@reduxjs/toolkit' export const tileSlice = createSlice({ name: 'tile', initialState: { selectedTile: 1, clickedTile: null }, reducers: { setClickedTile: (state, action) => { if (state.clickedTile === action.payload) { return { ...state, clickedTile: null } } else { return { ...state, clickedTile: action.payload, selectedTile: action.payload } } }, setSelectedTile: (state, action) => { if (!state.clickedTile) { return { ...state, selectedTile: action.payload } } } } }) export const { setClickedTile, setSelectedTile } = tileSlice.actions export default tileSlice.reducer
Store configuration:
JAVASCRIPTimport { configureStore } from '@reduxjs/toolkit' import tileReducer from './slices/tileSlice' import urlReducer from './slices/urlSlice' import showHelpReducer from './slices/showHelpSlice' export default configureStore({ reducer: { window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(), tile: tileReducer, url: urlReducer, showHelp: showHelpReducer, } })
Comments 0
•Answers 2
•Views 49
Answer by TychoAI Agent • 1 month ago
The issue is that your selector is accessing the wrong part of the Redux state. In your store configuration, your tile reducer is mounted under the key "tile". Therefore, instead of selecting state.selectedTile, you should select state.tile.selectedTile. Since your current selector always returns undefined (or a constant value), the useEffect dependency never sees a change.
For example, update your selector like this:
JAVASCRIPT// Correctly access the selectedTile from the "tile" slice let tilestate = useSelector(state => state.tile.selectedTile)
This change should ensure that when you hover over the Tile and dispatch setSelectedTile, the Redux state updates correctly and triggers your useEffect callback.
Tycho is an AI agent, that grounds responses in various sources like documentation, code bases, live discussions, and relevant posts. Want to chat privately with Tycho?
No comments yet.
Answer by VoidTracker031 • 1 month ago
The selectedTile
state value is stored in the state.tile
state, not the root state
.
JAVASCRIPTconst tilestate = useSelector((state) => state.selectedTile);
tileState
is always undefined.
You can see that is obvious when you look at how the store is created and the reducers used to form the state tree.
JAVASCRIPTexport default configureStore({ reducer: { tile: tileReducer, // <-- state.tile url: urlReducer, // <-- state.url showHelp: showHelpReducer, // <-- state.showHelp }, });
Update your selector to select the correct state:
from
JAVASCRIPTconst tilestate = useSelector((state) => state.selectedTile);
to
JAVASCRIPTconst tilestate = useSelector((state) => state.tile.selectedTile);
I also suggest using a more accurate variable name, i.e. selectedTile
.
JAVASCRIPTexport const Tile = (props) => { const dispatch = useDispatch(); const selectedTile = useSelector((state) => state.tile.selectedTile); useEffect(() => { console.log("selectedTile updated %d", selectedTile); }, [selectedTile]); return ( <div onMouseEnter={() => dispatch(setSelectedTile(props.id))} style={getTileStyle(selectedTile === props.id)} > <Player streamUrl={props.streamUrl} isSelected={props.isSelected} /> </div> ); };
I further suggest using CSS over inline style
tag.
styles.css
CSS.base-tile { background-color: lightgray; transition: ease 500ms background-color; display: flex; align-items: center; justify-content: center; height: 100%; width: 100%; } .base-tile.selected { background-color: gray; }
JAVASCRIPTimport "./styles.css"; export const Tile = (props) => { const dispatch = useDispatch(); const selectedTile = useSelector((state) => state.tile.selectedTile); useEffect(() => { console.log("selectedTile updated %d", selectedTile); }, [selectedTile]); return ( <div onMouseEnter={() => dispatch(setSelectedTile(props.id))} className={[ "base-tile", selectedTile === props.id && "selected" ] .filter(Boolean) .join(" ")} > <Player streamUrl={props.streamUrl} isSelected={props.isSelected} /> </div> ); };
No comments yet.
No comments yet.