尽管 Redux 状态发生变化,但 useSelector 钩子在 React 组件中并未更新

问题描述 投票:0回答:1

我正在 React 中创建一个打字游戏,并使用 ReduxToolkit 来管理状态。在我的 DesktopSlice 中,我正在跟踪某些面板是打开还是关闭。在我的 **Console 组件中,我使用 useSelector 挂钩从桌面切片获取面板状态。问题是 useSelector 始终返回面板对象的初始状态,即使状态已更新。 我有一个 Console 组件,用于运行命令,还有一个 PanelsWrapper 组件,用于显示我的面板。

  • main.tsx
    • 应用程序.tsx
      • 控制台.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)不会出现此问题。

任何人都可以帮助我了解可能导致此问题的原因吗?

编辑 我解决了这个问题。问题是我在组件上使用 addEventListener 而不是 onKeyDown,并且组件永远无法拥有更新的状态。

javascript reactjs redux
1个回答
0
投票

你可以尝试一下吗

const {panels} = useSelector((state: RootState) => state.desktop)
。我认为你应该解构

© www.soinside.com 2019 - 2024. All rights reserved.