rematchjs 上的 Hook 调用无效

Posted

技术标签:

【中文标题】rematchjs 上的 Hook 调用无效【英文标题】:Invalid Hook call on rematchjs 【发布时间】:2022-01-06 15:33:38 【问题描述】:

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

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

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

    您的 React 和渲染器版本可能不匹配(例如 React DOM) 您可能违反了 Hooks 规则 您可能在同一个应用程序中拥有多个 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"   />
          <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;

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

【问题讨论】:

themeChanger=DispatchThemes 是一个事件吗?如果是,那么我们将违反 hooks 实现。文档说“不要调用事件处理程序”。请提供有关 ThemeSwitcher 的更多信息。我不确定,但我认为这可能会导致问题。 请贴出ThemeSwitcher的代码。至少与themeChanger prop 相关的部分。 @GabrielePetrioli 我添加了代码并尝试了一点,但我无法让它工作 【参考方案1】:

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

您可以将 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);

【讨论】:

以上是关于rematchjs 上的 Hook 调用无效的主要内容,如果未能解决你的问题,请参考以下文章

Hooks 错误:在 Windows 上使用 NextJS 或 ReactJS 的 Hook Call 无效

Hook CreateProcess

项目上的 React Hook

调用自定义挂钩时挂钩调用无效

Material UI 无效的钩子调用

linux内核有没有hook机制