我正在 React 中创建一个打字游戏,并使用 Redux 和 Toolkit 来管理状态。在我的 DesktopSlice 中,我正在跟踪某些面板是打开还是关闭。在我的 **Console 组件中,我使用 useSelector 挂钩从桌面切片获取面板状态。问题是 useSelector 始终返回面板对象的初始状态,即使状态已更新。 我有一个 Console 组件,用于运行命令,还有一个 PanelsWrapper 组件,用于显示我的面板。
在 PanelsWrapper 面板显示正确,但在我的 Console.tsx 中,状态始终处于初始状态。
这是我的 DesktopSlice 代码:
import { createSlice } from "@reduxjs/toolkit";
import type { PayloadAction } from "@reduxjs/toolkit";
import { PANELS } from '../../data/panels';
type VisiblePanels = {[key in PANELS]?: boolean}
export type DesktopState = {
panels: VisiblePanels
}
const initialState: DesktopState = {
panels: {
[PANELS.FRIDGE]: false,
[PANELS.WORKTOP]: false,
[PANELS.RECIPEBOOK]: false,
}
};
export const desktopSlice = createSlice({
name: "desktop",
initialState,
reducers: {
toggleOpenPanel: (state, action: PayloadAction<{panelType: PANELS, opened?: boolean}>) => {
state.panels[action.payload.panelType] = action.payload.opened;
},
},
});
export const { toggleOpenPanel} = desktopSlice.actions;
export default desktopSlice.reducer;
这是我的 Console.tsx 组件代码:
const Console : FC = () => {
const inputRef = useRef<HTMLInputElement>(null);
const [consoleLog,setConsoleLog] = useState<ICommandLine[]>([]);
const openedPanels = useSelector((state: RootState) => state.desktop.panels);
const dispatch = useDispatch();
const focusConsole = () => {
inputRef.current && inputRef.current.focus();
}
const enterCommand = () => {
if(inputRef.current && inputRef.current.value){
//get command value
const command = inputRef.current.value;
console.log(openedPanels);
//interpret the command and get a response
const res : commandResponse | undefined = runCommandInterpreter(command);
if(res){
const cmdLine : ICommandLine = {
command: command,
info: res.message,
infoType: res.code
}
setConsoleLog(oldArray => [...oldArray,cmdLine]);
}
//clear the input
inputRef.current.value="";
}
}
const runCommandInterpreter = (input:string) : commandResponse | undefined => {
const command_args = input.trim().split(" ");
const command = command_args[0];
const command_parameters = command_args.slice(1);
switch(command){
case COMMAND.OPEN:
case COMMAND.CLOSE:
const panelName = command_parameters.join(" ");
const panel = getPanelByName(panelName);
const opened = command === COMMAND.OPEN;
if(panel){
dispatch(toggleOpenPanel({panelType: panel, opened: opened}));
return sendResponse(COMMAND_CODE.OK);
} else {
return sendResponse(
COMMAND_CODE.ERROR,
`${panelName} is not a valid PANEL name.`
);
}
}
}
const handleKeyDown = (e:KeyboardEvent) => {
switch(e.key){
case 'Enter':
enterCommand();
break;
}
}
useEffect(() => {
inputRef.current?.addEventListener("keydown",handleKeyDown);
},[]);
return (
<StyledConsole onClick={focusConsole}>
<StyledConsoleHistory>
{
consoleLog.map((command,index) => (
<CommandLine
key={`${index}-${command.command}`}
command={command.command}
info={command.info}
infoType={command.infoType}
/>
))
}
</StyledConsoleHistory>
<StyledConsoleLabel>
<StyledConsoleCommand>
What would you like to do?
</StyledConsoleCommand>
<StyledConsoleInput type="text" ref={inputRef} />
</StyledConsoleLabel>
</StyledConsole>
)
}
export default Console
问题是openedPanels总是返回desktopSlice.panels的初始状态,并且即使Redux存储中的状态正确更新也不会更新。其他也使用 useSelector 的组件(例如 PanelsWrapper)不会出现此问题。
任何人都可以帮助我了解可能导致此问题的原因吗?
编辑 我解决了这个问题。问题是我在组件上使用 addEventListener 而不是 onKeyDown,并且组件永远无法拥有更新的状态。
你可以尝试一下吗
const {panels} = useSelector((state: RootState) => state.desktop)
。我认为你应该解构