我有一个非常简单的
Tile
组件,我想在它悬停时改变颜色(以及其他关联的组件)。现在,当组件悬停在其上时,它会设置 Redux 状态。设置状态后,我想以不同的颜色重新渲染组件(和其他组件)。我正在使用 useEffect
React 钩子,它依赖于我用 useSelector
声明的 Redux 状态。
当这段代码运行时,我可以在 Redux-DevTools 浏览器插件中成功看到 Redux 状态更新,但
useEffect
函数永远不会被触发。有人可以帮我理解为什么吗?
瓷砖:
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;
平铺状态减速器:
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
店铺:
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,
}
})
我还尝试将回调连接到
store.getState()
,但这也总是返回 redux 状态的初始值,而不是更新后的状态。
selectedTile
状态值存储在state.tile
状态中,而不是根state
。
const tilestate = useSelector((state) => state.selectedTile);
tileState
始终未定义。
当您查看存储的创建方式以及用于形成状态树的减速器时,您会发现这一点是显而易见的。
export default configureStore({
reducer: {
tile: tileReducer, // <-- state.tile
url: urlReducer, // <-- state.url
showHelp: showHelpReducer, // <-- state.showHelp
},
});
更新您的选择器以选择正确的状态:
来自
const tilestate = useSelector((state) => state.selectedTile);
到
const tilestate = useSelector((state) => state.tile.selectedTile);
我还建议使用更准确的变量名称,即
selectedTile
。
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>
);
};
我进一步建议使用 CSS 而不是内联
style
标签。
样式.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;
}
...
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>
);
};