6

I'm trying to learn to create hooks so I can re-use data that I have to change in different components.

I'm using Material UI's Tabs and need to use useTab, a custom hook to change the tab 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;

I know it does this with child functions in the docs, but I'm trying to not just copy and paste and do it in my own way.

Here is my custom useTab hook:

import {useState, useEffect} from 'react';

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

I'm of course getting an error I can't use a hook inside of a function, but I'm confused how else to do this.

How can I change tabValue from useTabs?

2 Answers 2

0

The error is probably here:

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

You're violating one of the primary Rules of Hooks:

Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function.

The reason for this rule is a bit complex but it basically boils down to the idea that hooks should only be called at the top level of a React functional component because they must be guaranteed to run every time the component function is run.

Hence why you're getting an error "I can't use a hook inside of a function"...

At any rate, it is unclear why you are using a custom hook with a useEffect() here. That seems completely unnecessary - a regular useEffect() hook inside of your nav component should more than suffice:

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>
    ); 
};
Sign up to request clarification or add additional context in comments.

2 Comments

Hi I'm using a custom hook so I can use TabPane in another component....
@kinx In that case you should simply move your tabValue state up a few levels in your component hierarchy so that you can make it available (pass it down as props) to multiple components. This concept is called "lifting up state" and understanding it is critical to how you manage state in your React app. It has nothing to do with hooks. reactjs.org/docs/lifting-state-up.html
-1
const [data, setData] = useState(initialValue);

function handleClick() {
  setData(newValue); // update the state
}

<button onClick={handleClick}>Click Me</button>

1 Comment

Although this code might answer the question, I recommend that you also provide an explanation what your code does and how it solves the problem of the question. Answers with an explanation are usually more helpful and of better quality, and are more likely to attract upvotes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.