Flimzy_Programmer
Flimzy_Programmer

Reputation: 543

Using hooks in nested functions

I'm trying to rewrite a React class component into a functional hooks-based component, but i cannot figure out how to do it. The component logic and JSX looks something like this:

export class LeftPanel extends React.Component<ILeftPanelProps, ILeftPanelState> {

const [menuItemsFullList, setMenuItemsFullList] = useState([{links: []}] as any[]);

useEffect(() => {
    const { links } = props;

    setMenuItemsFullList(links);
}, props.links);
....

return (<>
        <SearchBox
            onChange={_onSearch}
            onClear={_onClearSearchBox}
        />
            <NavList
                listEntries={[menuItems]}
            />
</>)

Where the function i'm currently rewriting is onClearSearchBox:

private _onClearSearchBox() {
    this.setState({ menuItems: { ...this.state.menuItemsFullList } });
}

I tried naively rewriting it using hooks which turned the setState into this:

function onClearSearchBox() {
     useEffect(() => setMenuItems(menuItemsFullList));
}

This does not work and i do not know how to restructure the code, as i cannot call hooks inside a non-React component function. Moving it into the React component function as an inner function does not work either.

The error message i'm getting is:

Uncaught Invariant Violation: Invalid hook call. Hooks can only be called inside of the body of a function component...

I believe my mindset is still stuck to the class-based structure, as i cannot figure out how i would go about and refactoring the LeftPanel. How should i go about refactoring _onClearSearchBox to make it work with hooks?

Upvotes: 0

Views: 6266

Answers (1)

James
James

Reputation: 82096

useEffect is the wrong hook for this, from the docs:

If you’re familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.

In your example, you need control over when to want to call the code e.g. on a button click. I'd say useCallback would be the most appropriate hook here:

const onClearSearchbox = useCallback(() => {
  setMenuItemsFullList(props.items);
}, [props.items]);
...
<SearchBox onClear={onClearSearchBox} ... />

Upvotes: 1

Related Questions