【问题标题】:Invalid Hook Call when executing anonymous function using button onClick使用按钮 onClick 执行匿名函数时挂钩调用无效
【发布时间】:2021-02-07 09:25:44
【问题描述】:

我正在尝试在 React 中创建一个提交按钮。

这是我必须处理 onClick 事件的代码:

const handleEditProfileSubmit = () => {
    const authContext = useContext(AuthContext);

    if (newUserEntityDetails.username !== "") {
        newUserEntityDetails.uid = authContext.user.uid;
        axios.put(ENDPOINT + authContext.user.uid, newUserEntityDetails).then((res: any) => console.log(res)).catch((e: any) => console.log(e));
    }
};

这是我的按钮代码:

<Button onClick={handleEditProfileSubmit}>Submit</Button>

其中使用了Button material-ui组件。

我尝试过使用onClick={() =&gt; {handleEditProfileSubmit}},但是这导致提交按钮什么也不做。

我也尝试将handleEditProfileSubmit 常量转换为函数并执行onClick={handleEditProfileSubmit()},但是这会得到相同的错误。

我不确定自己做错了什么。 axios API 调用在我代码的其他部分工作正常,所以我认为这与 API 调用无关。

编辑:这是整个组件的代码。

import React, {useContext} from "react";
import Navbar from "../components/navbar";
import { Redirect } from "react-router-dom";
import { AuthContext } from "../Auth";
import { Container } from "@material-ui/core";
import { Grid } from "@material-ui/core";
import { Paper, Card, CardContent } from "@material-ui/core";
import { MenuList, MenuItem} from "@material-ui/core";
import { Typography } from "@material-ui/core";
import { TextField } from "@material-ui/core";
import { Button } from "@material-ui/core";

const axios = require('axios');
const ENDPOINT = 'http://localhost:3000/api/user/';

var newUserEntityDetails = {
    uid: "",
    username: ""
}

const authContext = useContext(AuthContext);

const handleEditProfileSubmit = () => {

        if (newUserEntityDetails.username !== "") {
            newUserEntityDetails.uid = authContext.user.uid;
            var a = axios.put(ENDPOINT + authContext.user.uid, newUserEntityDetails).then((res: any) => console.log(res)).catch((e: any) => console.log(e));
            console.log(a);
        }
        
};


const Settings = () => {

    // If there is no user in the session
    if (authContext.user == null) {
        return(<Redirect to={"/login"} />);

    } else {
        return(
            <>
                <Navbar />
                <Container maxWidth="lg">
                <Grid container spacing={3} direction="row" style={{ minHeight: "90vh" }}>
                    <Grid item xs={3}>
                        <Paper>
                            <MenuList>
                                <MenuItem>
                                    <Typography variant="body1">Profile</Typography>
                                </MenuItem>
                                <MenuItem>
                                    <Typography variant="body1">Account Settings</Typography>
                                </MenuItem>
                                <MenuItem>
                                    <Typography variant="body1">Delete Account</Typography>
                                </MenuItem>
                            </MenuList>
                        </Paper>
                    </Grid>
                    <Grid item xs={6}>
                        <Card>
                            <CardContent>
                            <Typography variant="subtitle2" gutterBottom>
                                Change Username
                            </Typography>
                            <TextField
                                id="outlined-helperText"
                                label="Change Username"
                                helperText="Username must be unique"
                                variant="outlined"
                                onChange = { input => {
                                    newUserEntityDetails.username = input.target.value;
                                }}
                            />
                            <Button onClick={() => {handleEditProfileSubmit}}>Submit</Button>
                            </CardContent>
                        </Card>
                    </Grid>
                </Grid>
                </Container>
            </>
        );
    }
};

export default Settings;

P.S 我的项目经理告诉我要避免对组件使用类,因此我正在尝试编写功能组件

【问题讨论】:

  • 两件事......第一:你不能在内部函数中实例化 React Hook。取而代之的是,将useContext 拉到组件的顶层。第二:onClick={() =&gt; {handleEditProfileSubmit}} 这个语法没有意义。你的意思可能是onClick={() =&gt; handleEditProfileSubmit()}

标签: reactjs typescript axios react-hooks


【解决方案1】:

您在函数内部调用 Hooks,这就是导致问题的原因。 根据React docsDon’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function. By following this rule, you ensure that Hooks are called in the same order each time a component renders

声明你的函数的钩子顶部,你应该没问题!!。

...all imports

const Settings = () => {
   const authContext = useContext(AuthContext); //This is what you need to do.

   const handleEditProfileSubmit = () => {
        if (newUserEntityDetails.username !== "") {
            newUserEntityDetails.uid = authContext.user.uid;
            var a = axios.put(ENDPOINT + authContext.user.uid, newUserEntityDetails).then((res: any) => console.log(res)).catch((e: any) => console.log(e));
            console.log(a);
        }
        
  };
....

【讨论】:

  • 当我把东西放在const 之外时,我遇到了同样的问题,并且根本没有呈现任何页面。我认为这与我没有为我的组件使用类有关。有什么办法可以把它放在const 之外,而不必在 React 中使用类?
  • 你能为它创建一个小提琴/stackblitz吗?会看看的。
  • 我刚刚编辑了帖子以包含我的整个组件代码。谢谢!
  • 查看我的评论。你不是那样打电话给handleEditProfileSubmit
  • @Meowmi 你应该使用 useState 来处理 username 而不是全局对象。我对您的代码进行了一些更改并创建了一个stackbliz here
【解决方案2】:

你需要在handleEditProfileSubmit之外有const authContext = useContext(AuthContext);

【讨论】:

  • 当我把它放在const 之外时,我得到一个无效的钩子调用并且没有任何页面被渲染
  • 整个组件是怎么写的?如果能看到就更好了。
  • 我刚刚编辑了帖子以包含我的代码,感谢您的建议
  • 你需要在Setting里面定义const authContext = useContext(AuthContext);handleEditProfileSubmit
猜你喜欢
  • 2021-12-07
  • 1970-01-01
  • 2020-08-13
  • 2021-06-17
  • 2021-12-23
  • 2020-09-09
  • 1970-01-01
  • 1970-01-01
  • 2019-10-27
相关资源
最近更新 更多