React - What's the best way of passing a state setter function to a helper function from a component?

Viewed 22

For context, I'm new to React, in case this is something commonly asked. I'm still getting used to all the terminology, so my apologies if anything sounds confusing.

Say there is a component in which we make use of the state hook. Let's say:

function Example() {
    const [count, setCount] = useState(0);
    const [showTable, setShowTable] = useState(false);

    // some logic follows here

    // and some rendering
}

If I don't want to smush all logic into the component, it would make sense to create some helper functions. Each one gets its own file. And the "useEffect" hook gets a file of its own as well. Something like:

import useInitExample from './hooks/useInitExample';

function Example() {
    const [count, setCount] = useState(0);
    const [showTable, setShowTable] = useState(false);

    const someParam = {
        ...
    }

    useInitExample(someParam);
    
    // rendering happening here
}

useInitExample is importing and using a bunch of the aforementioned helper functions.

Now, assuming that a helper function needs to either call a setter, or needs to know a current state, I assume we need to pass it along from the main component to the useInitExample file, and from there to the helper functions. So something like this:

import useInitExample from './hooks/useInitExample';

function Example() {
    const [count, setCount] = useState(0);
    const [showTable, setShowTable] = useState(false);

    const someParam = {
        count,
        setCount,
        showTable
    }

    useInitExample(someParam);
    
    // rendering happening here
}

and subsequently, in useInitExample.js, I would need to do something like:

import helperFunction from './../helpers/helperFunction'
import anotherHelper from './../helpers/anotherHelper'

function useInitExample(someParam) {
    
    const result = helperFunction({
        count: someParam.count,
        setCount: someParam.setCount
    })

    const result2 = anotherHelper({
        count: someParam.count,
        showTable: someParam.showTable
    })

    ...
}

Aside from the example above not making much actual sense, with a complex component, this approach can obviously get out of hand fast, with passing a ton of things between functions, and things can get cluttered. Especially if a helper function makes use of further helper functions.

I've been looking at alternative ways to structure this. So far, I've been looking at Context, but from what I can tell, that only helps with nested components, not helper functions.

I feel dirty about using redux to solve this. I also thought about passing all setters and states to every function as a parameter, but that also feels dirty.

I also tried isolating all instances of useState() for a component into a separate file to be imported by said helper functions and the component as well, but alas, useState() doesn't work outside of a component (which makes sense).

Is there any way to avoid having to pass setters and states in the way that I describe above?

Before you ask, the helper functions described above are specific to a component and not intended to be reused by other components.

Thanks!

1 Answers

in case which the helper functions described above are specific to a component and not intended to be reused by other components, it indeed means you have a lot of logic to write and there is no one to minimize it or structure it differently. if you want the code less verbose i might suggest to receive to parameters to useInitExample as destruct object and then you can pass them like:

function useInitExample({ count, setCount }) {
    
    const result = helperFunction({ count, setCount })

    const result2 = anotherHelper({ count, setCount })

    ...
}

in case the state should be shared in several components/hooks you can use React.Context, it indeed a great and elegant solution.

Related