我在React中创建了一个打字游戏,使用Redux配合Toolkit来管理状态,在DesktopSlice中,我记录了某些面板是打开还是关闭,在Console组件中,我使用useSelector钩子从桌面slice中获取面板状态,问题是useSelector总是返回面板对象的初始状态。我有一个运行命令的Console组件,还有一个显示面板的PanelsWrapper**组件。
- main.tsx
- App.tsx
- Console.tsx
- PanelsWrapper.tsx
在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。
有人能帮助我了解可能导致此问题的原因吗?
EDIT我修复了这个问题。问题是我在我的组件上使用了addEventListener而不是onKeyDown,组件永远不会有更新的状态。
1条答案
按热度按时间4si2a6ki1#
你能试试
const {panels} = useSelector((state: RootState) => state.desktop)
吗?我想你应该解构一下