2

我将有一个reactjs网站,我想从“rtk”迁移到“rematch”。

rematch在我的导航中,我将有一个主题切换器,它在商店中执行调度。但我总是得到错误:

错误:无效的挂钩调用。钩子只能在函数组件的主体内部调用。这可能由于以下原因之一而发生:

  1. 你可能有不匹配的 React 版本和渲染器(例如 React DOM)
  2. 您可能违反了 Hooks 规则
  3. 您可能在同一个应用程序中拥有多个 React 副本有关如何调试和修复此问题的提示,请参阅https://reactjs.org/link/invalid-hook-call 。

这是我的导航

import React, { useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { languages, useTypedTranslation } from '../definitions/language';
import { matchPath, useHistory } from 'react-router-dom';
import { routes } from '../definitions/routes';
import MeegoTech from '../assets/meego.svg';
import { Theme, createStyles, AppBar, Box, FormControlLabel, FormGroup, IconButton, Menu, MenuItem, Toolbar, Typography, Switch, useMediaQuery } from '@mui/material';
import { makeStyles } from '@mui/styles';
import { PersonOutline } from '@mui/icons-material';
import MenuIcon from '@mui/icons-material/Menu';
import ThemeSwitcher from '../theme/themeSwitcher';
import { useDispatch } from 'react-redux';
import { Dispatch } from '../store/configureStore';

const Navigation: React.FC = () => {

  //Authentication
  const [auth, setAuth] = React.useState(true);
  const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);

  //Translation
  const { t } = useTypedTranslation();

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setAuth(event.target.checked);
  };

  const handleMenu = (event: React.MouseEvent<HTMLElement>) => {
    setAnchorEl(event.currentTarget);
  };

  const handleClose = () => {
    setAnchorEl(null);
  };

  // Get OS-level preference for dark mode
  const prefersDarkMode: boolean | undefined = useMediaQuery("(prefers-color-scheme: dark)");

//This Function throws the error
  function DispatchThemes(themeMode: boolean | undefined){
    const dispatch = useDispatch<Dispatch>()
    useEffect(() => {
      dispatch.themeModel.setDarkModeAsync(themeMode);
    }, []) 
    return <></> 
  }

  return (
    <Box sx={{ flexGrow: 1 }}>
      <FormGroup>
        <FormControlLabel
          control={
            <Switch
              color="default"
              checked={auth}
              onChange={handleChange}
              aria-label="login switch"
            />
          }
          label={auth ? 'Logout' : 'Login'}
        />
      </FormGroup>
      <AppBar position="static" style={{ backgroundColor: "rgb(255,255,255" }}>
        <Toolbar>
          <IconButton
            size="large"
            edge="start"
            color="inherit"
            aria-label="menu"
            sx={{ mr: 2 }}
          >
            <MenuIcon fontSize="large" style={{ color: "rgb(0,0,0)" }} />
          </IconButton>
          <img src={MeegoTech} style={{ height: "100px", width: "auto", marginRight: "15px" }} alt="Meego Technologies Brand" />
          <Typography variant="h6" component="div" sx={{ flexGrow: 1 }} style={{ color: "rgb(0,0,0)" }}>
            {t("layout", "meegoTech")}
          </Typography>
/* If i'll switch this switcher the error will be thrown */
          <ThemeSwitcher useOs={false} themeChanger={DispatchThemes} />
          {auth && (
            <div>
              <IconButton
                size="large"
                style={{ color: "rgb(0,0,0)" }}
                aria-label="account of current user"
                aria-controls="menu-appbar"
                aria-haspopup="true"
                onClick={handleMenu}
              >
                <PersonOutline fontSize="large" />
              </IconButton>
              <Menu
                id="menu-appbar"
                anchorEl={anchorEl}
                anchorOrigin={{
                  vertical: 'top',
                  horizontal: 'right',
                }}
                keepMounted
                transformOrigin={{
                  vertical: 'top',
                  horizontal: 'right',
                }}
                open={Boolean(anchorEl)}
                onClose={handleClose}
              >
                <MenuItem onClick={handleClose}>Profile</MenuItem>
                <MenuItem onClick={handleClose}>My account</MenuItem>
              </Menu>
            </div>
          )}
        </Toolbar>
      </AppBar>
    </Box>
  );

}

export default Navigation

这是 的代码ThemeSwitcher

interface ThemeSwitcherOptions {
  useDark?: boolean;
  themeChanger: (useDark?: boolean) => void;
}

const ThemeSwitcher: React.FC<ThemeSwitcherOptions> = (props) => {

  const expandedProps = {
    ...props,
    useDark: props.useDark || false,
  };

  const [theme, setTheme] = useState(expandedProps);

  const handleSwitch = (_e: any, checked: boolean) => {
    setTheme({ ...theme, useDark: checked });
    theme.themeChanger(checked);
  };

  return (
    <>
      <FormControlLabel
        style={{color:'rgb(0,0,0)'}}
        labelPlacement="end"
        label=""
        control={
          <ThemeSwitch
            checked={theme.useDark}
            onChange={handleSwitch}
          />
        }
      />
    </>
  );
}

export default ThemeSwitcher;

有谁知道为什么会抛出错误?

4

1 回答 1

0

DispatchThemes是一个组件,你甚至返回 jsx。但是您将它作为组件传递并themeChanger在事件处理程序中ThemeSwitcher调用它。theme.themeChanger所以你不要把它当作一个组件。钩子只允许在被渲染的组件中使用。

您可能可以将 DispatchThemes 函数更改为

const dispatch = useDispatch<Dispatch>(); // put the dispatch outside the function

//This function should not throw an error anymore
function DispatchThemes(themeMode: boolean | undefined){
  // remove the useEffect as well
  dispatch.themeModel.setDarkModeAsync(themeMode);
}
于 2021-12-04T20:23:32.330 回答