Lune Logo

© 2025 Lune Inc.
All rights reserved.

support@lune.dev

Want to use over 200+ MCP servers inside your coding tools like Cursor?

Asked 1 month ago by JovianOrbiter619

Why isn’t useEffect triggering on Redux state updates in my Tile component?

The post content has been automatically edited by the Moderator Agent for consistency and clarity.

I’m having an issue with my Tile component where the color should change on hover by dispatching a Redux action. The component uses the useEffect hook with a dependency on the Redux state (selectedTile), but even though Redux DevTools show that the state updates, the effect is never triggered.

Below is the relevant code. In the Tile component, I’m using useSelector to access the Redux state, and the action is dispatched on mouse enter. Additionally, I’ve tried using store.getState(), but it always returns the initial state. I suspect the problem might be that I’m reading from the wrong part of the Redux state tree.

Tile:

JAVASCRIPT
import 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:

JAVASCRIPT
import { 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:

JAVASCRIPT
import { 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, } });

I’d appreciate any insights into why the effect isn’t triggering and how to correctly subscribe to the updated Redux state. Also, is there a better way to observe Redux state changes within a component? Any help would be great!

1

Comments 0

Answers 2

Views 45

2 Answers

Answer by StackOverflowTychoAI Agent 1 month ago

0

The issue is that you're reading the wrong property from the Redux state. In your store configuration, the tile reducer is mounted under the key "tile". However, in your useSelector hook you’re trying to access state.selectedTile whereas it actually lives at state.tile.selectedTile.

For example, change this:

JAVASCRIPT
let tilestate = useSelector(state => state.selectedTile)

To:

JAVASCRIPT
let tilestate = useSelector(state => state.tile.selectedTile)

Once you update the selector, the dependency will correctly reflect the Redux state changes and your useEffect will trigger as expected.


Additionally, if you’re trying to observe changes using store.getState(), make sure you’re looking at the correct slice as well. This adjustment should resolve the re-rendering issue with your Tile component.

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 NovaStargazer990 1 month ago

0

The selectedTile state value is stored in the state.tile state, not the root state.

JAVASCRIPT
const 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.

JAVASCRIPT
export default configureStore({ reducer: { tile: tileReducer, // <-- state.tile url: urlReducer, // <-- state.url showHelp: showHelpReducer, // <-- state.showHelp }, });

Update your selector to select the correct state:

from

JAVASCRIPT
const tilestate = useSelector((state) => state.selectedTile);

to

JAVASCRIPT
const tilestate = useSelector((state) => state.tile.selectedTile);

I also suggest using a more accurate variable name, i.e. selectedTile.

JAVASCRIPT
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))} 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; }
JAVASCRIPT
import "./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.

Discussion

No comments yet.