【问题标题】:ReactJS : Invalid hook call. Hooks can only be called inside of the body of a function componentReactJS:无效的钩子调用。 Hooks 只能在函数组件的主体内部调用
【发布时间】:2021-10-18 14:53:21
【问题描述】:

在我的子方法之一上调用 useEffect 函数时,结果

ReactJS : 无效的钩子调用。 Hooks 只能在内部调用 函数组件的主体。

流动

onClick(message) --> call CallGetAMIDetails(message) --> Call Loaddata(message) --> Perform REST Call and -->Returns Array of String

但是我的类已经是函数组件了

import React, {useEffect, useState} from 'react';

import {DashboardLayout} from '../components/Layout';
import Select from 'react-select'


const options = [
    {value: 'ami-abc*', label: 'ami-abc'},
    {value: 'ami-xyz*', label: 'ami-xyz'},
]



const DiscoverAMIPage = () => {

    function Loaddata() {
        const [error, setError] = useState(null);
        const [isLoaded, setIsLoaded] = useState(false);
        const [items, setItems] = useState([]);

        useEffect(() => {
            fetch("http://localhost:10000/connections")
                .then(res => res.json())
                .then(
                    (result) => {
                        setIsLoaded(true);
                        setItems(result);
                    },
                    // Note: it's important to handle errors here
                    // instead of a catch() block so that we don't swallow
                    // exceptions from actual bugs in components.
                    (error) => {
                        setIsLoaded(true);
                        setError(error);
                    }
                )
        }, [])

        if (error) {
            return []
        } else if (!isLoaded) {
            return []
        } else {
            return (
                items
            );
        }
    }

    function CallGetAMIDetails(message) {
        return Loaddata(message)

    }

    const [message, setMessage] = useState('');
    const [items, setItems] = useState([]);

    return (
        <DashboardLayout>
            <h2>Discovered AMI</h2>
    <Select
    onChange={e => {
        setMessage(e.value);
        setItems(CallGetAMIDetails(e.value));
    }}
    options={options}
    />
    {console.log("----")}
    <h2>{items}</h2>
    {console.log("----")}

    </DashboardLayout>
)
}

export default DiscoverAMIPage;

我在这里做错了什么?

【问题讨论】:

  • 我认为由于 Loaddata 被调用,react 并不认为它是一个组件,而是一个常规的 JS 函数。见Only call hooks from react functions
  • 错误告诉你你在做什么——钩子只能在组件函数的“顶层”调用,但你在 Loaddata() 函数中调用 useEffect(),即不是您的 DiscoverAMI 组件的顶层
  • 我会说清楚的。发生这种情况是因为您在“DiscoverAMIPage”中有“Loaddata”

标签: javascript reactjs


【解决方案1】:

摆脱Loaddata。您将 组件普通功能 混为一谈,并试图互换使用它们,这会导致结构严重过度设计和损坏。

DiscoverAMIPage 是您的组件。该组件内部应该是您对useStateuseEffect 的调用。 useState 调用定义组件的状态值,useEffect 调用在重新渲染时依赖关系发生变化时调用操作。简化您的工作。

例如:

const DiscoverAMIPage = () => {

    const [error, setError] = useState(null);
    const [isLoaded, setIsLoaded] = useState(false);
    const [items, setItems] = useState([]);
    const [message, setMessage] = useState('');

    useEffect(() => {
        fetch("http://localhost:10000/connections")
            .then(res => res.json())
            .then(
                (result) => {
                    setIsLoaded(true);
                    setItems(result);
                },
                // Note: it's important to handle errors here
                // instead of a catch() block so that we don't swallow
                // exceptions from actual bugs in components.
                (error) => {
                    setIsLoaded(true);
                    setError(error);
                }
            )
    }, [])

    return (
        <DashboardLayout>
            <h2>Discovered AMI</h2>
            <Select
                onChange={e => setMessage(e.value)}
                options={options}
            />
            <h2>{items}</h2>
        </DashboardLayout>
    );
}

现在您有一个具有 4 个状态值和 1 个效果的组件。这种效果是在组件第一次加载时执行 AJAX 操作(之后不再加载),并且该操作在完成时更新状态。该状态更新将使用其新数据重新渲染组件。从这个起点开始,您可以继续开发您的功能。


编辑:基于下面的 cmets,听起来您还想在事件处理程序中手动调用 AJAX 函数。为此,您可以将 AJAX 逻辑提取到一个函数中,并在事件处理程序和 useEffect 中调用该函数,就像您将功能提取到一个函数中以便从其他任何地方调用一样。

例如:

const loadData = () =>
    fetch("http://localhost:10000/connections")
        .then(res => res.json())
        .then(
            (result) => {
                setIsLoaded(true);
                setItems(result);
            },
            // Note: it's important to handle errors here
            // instead of a catch() block so that we don't swallow
            // exceptions from actual bugs in components.
            (error) => {
                setIsLoaded(true);
                setError(error);
            }
        );

useEffect(loadData, []);

现在您有一个独立执行 AJAX 操作的函数(useEffect 只是调用该函数),您可以在事件处理程序中调用该函数:

<Select
    onChange={e => {
        setMessage(e.value);
        loadData();
    }}
    options={options}
/>

如果您需要将选定的值传递给loadData,那么您可以像传递给setMessage 一样传递e.value。然后在loadData 中添加一个函数参数并根据需要使用它。

【讨论】:

  • 非常感谢,David 对我的帮助和教诲,我需要调用 LoadData 或等效项,以使用所选选项对方法进行每次更改。 sn-p 真的有助于理解这个概念,如果你能指出正确的方向如何调用它
  • @anish:澄清你需要做什么。 “我需要调用 LoadData”在此代码中没有任何意义,因为没有这样的函数,并且“选择选项”在您的原始代码中没有任何意义,因为没有任何值传递给 LoadData。当&lt;Select&gt;值发生变化时,具体需要做什么?
  • 用户将选择选择/下拉菜单。此选择将传递给函数调用并返回响应。结果将使用您显示的代码显示在 UI 中。我只是对功能组件和功能感到困惑。我已经更新了代码。给您带来困扰,我深表歉意
  • @anish:我已经通过一个示例更新了答案,说明了您可以如何做到这一点。基本上只需将 AJAX 操作提取到一个函数中,然后在需要的地方调用该函数。在useEffectchange 处理程序中,组件需要调用它的任何位置。
  • 你很慷慨。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-08
  • 2020-06-22
  • 2019-09-07
  • 1970-01-01
  • 2021-10-25
  • 2021-05-05
  • 2020-12-06
相关资源
最近更新 更多