You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Redux状态更新时useEffect钩子未触发的问题求助

Redux状态更新时useEffect钩子未触发的问题求助

我有一个简单的Tile组件,希望在hover时改变颜色(以及关联组件的样式)。目前我在组件hover时更新Redux状态,DevTools显示状态确实更新了,但监听该状态的useEffect钩子从未触发,组件也没有正确切换样式。以下是我的代码,麻烦帮忙排查问题:

Tile组件代码

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 Slice代码

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配置代码

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,
    }
})

问题排查与修复

我帮你找到了两个核心问题,修复后就能解决useEffect不触发和样式不更新的问题:

1. Store配置的致命错误

你把Redux DevTools的扩展函数错误地放到了reducer对象里!configureStore的reducer字段只能存放各个slice的reducer映射,DevTools是单独的配置项(而且@reduxjs/toolkit的configureStore默认已经启用了DevTools,不需要手动添加)。

修复后的Store代码:

import { configureStore } from '@reduxjs/toolkit'
import tileReducer from './slices/tileSlice'
import urlReducer from './slices/urlSlice'
import showHelpReducer from './slices/showHelpSlice'

export default configureStore({
    reducer: {
        // 移除错误放入的DevTools函数,只保留reducer映射
        tile: tileReducer,
        url: urlReducer,
        showHelp: showHelpReducer,
    },
    // 如果你需要自定义DevTools配置,可以加这个选项,默认启用状态下可以省略
    // devTools: process.env.NODE_ENV !== 'production'
})

2. useSelector的状态路径错误

因为你把tileReducer挂载到了store的tile字段下,所以Redux的state结构是{ tile: { selectedTile: ..., clickedTile: ... }, ... }。但你当前的useSelector直接取state.selectedTile,这会返回undefined(根state下没有这个字段),自然无法响应状态更新。

修复Tile组件里的useSelector:

// 错误写法
// let tilestate = useSelector(state => state.selectedTile)

// 正确写法:从state.tile子节点下获取selectedTile
let tilestate = useSelector(state => state.tile.selectedTile)

修复后的效果

当你完成以上两处修复后:

  • tilestate会正确同步Redux中tile.selectedTile的状态变化
  • 状态更新时useEffect会被触发,控制台会打印更新日志
  • 组件会根据tilestate === props.id的判断正确切换样式

备注:内容来源于stack exchange,提问作者Ed McKenna

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 14:33:05