如何从函数或事件内部的反应挂钩设置数据?

时间:2019-09-09 22:13:42

标签: javascript reactjs next.js

我正在尝试学习创建钩子,以便可以重复使用必须在不同组件中更改的数据。

我正在使用Material UI's Tabs,需要使用useTab,这是一个用于更改标签页ID的自定义钩子。

import React, { useContext } from 'react';
import { ProductsContext } from './ProductsContext';
import AppBar from '@material-ui/core/AppBar';
import Tabs from '@material-ui/core/Tabs';
import Tab from '@material-ui/core/Tab';
import { useTab } from '../../hooks/tab';

const ProductsNav = () => {
    const {products, categories, loading} = useContext(ProductsContext);
    const [tabValue] = useTab(0);

    const handleTabChange = (e, newTabValue) => {
        useTab(newTabValue);
    }

    return (
        <div className="products">
            <AppBar position="static">
                <Tabs value={tabValue} onChange={ handleTabChange }>
                    {
                        Array.from(categories).map(category => (
                            !category.unlisted && (<Tab label={category.title} key={category.id}/>)
                        ))
                    }
                </Tabs>
            </AppBar>

        </div>
    ); 
};

export default ProductsNav;

我知道它是通过文档中的子功能来完成此操作的,但我不仅尝试以自己的方式复制和粘贴并完成操作。

这是我自定义的useTab钩子:

import {useState, useEffect} from 'react';

export const useTab = (selectedTab) => {
    const [tabValue, setTabValue] = useState(0);
    useEffect(() => {
        setTabValue(selectedTab);
    }, []);
    return [tabValue];
}

我当然遇到了错误,我不能在函数内部使用钩子,但是我很困惑其他方法。

如何从useTabs更改tabValue?

1 个答案:

答案 0 :(得分:0)

错误可能在这里:

const handleTabChange = (e, newTabValue) => {
    useTab(newTabValue);
}

您违反了主要的Rules of Hooks之一:

  

请勿在循环,条件或嵌套函数中调用Hook。   相反,请始终在React函数的顶层使用挂钩。

这个规则的原因有点复杂,但是从根本上可以归结为这样的想法:在React功能组件的顶层只能调用 ,因为必须保证 在每次运行组件功能时运行。

因此,为什么会出现错误“我不能在函数内部使用钩子” ...

无论如何,目前尚不清楚为什么在这里使用带有useEffect()的自定义钩子。这似乎完全没有必要-导航组件内部的常规useEffect()钩子已经足够了:

const ProductsNav = () => {
    const {products, categories, loading} = useContext(ProductsContext);
    const [tabValue, setTabValue] = useState(0);

    const handleTabChange = (e, newTabValue) => {
        setTabValue(newTabValue);
    }

    return (
        <div className="products">
            <AppBar position="static">
                <Tabs value={tabValue} onChange={ handleTabChange }>
                    {
                        Array.from(categories).map(category => (
                            !category.unlisted && (<Tab label={category.title} key={category.id}/>)
                        ))
                    }
                </Tabs>
            </AppBar>

        </div>
    ); 
};