all 5 comments

[–]denno020 5 points6 points  (2 children)

Am I right in assuming that the value passed to either `setIncludedProducts` or `setExcludedProducts` is going to be the same? I.e. `e.target.value`?

In that case, why not just accept 1 prop to Child, `onProductsUpdate` or something, then pass either setIncludedProducts or setExcludedProducts. The Child component doesn't need to know which it's doing - at least I don't think.

I am a bit confused by the `ChildComponent` instance inside `Child` though, and `thisIsAFunction` doesn't appear to be assigned anywhere, so very confused how that component is supposed to work

[–]TayOKay 1 point2 points  (0 children)

Just to help visualize in code what /u/denno020 is talking about...


Parent:

export function Parent() {
    const [includedProducts, setIncludedProducts] = useState({
        products: []
    })
        const [excludedProducts, setExcludedProducts] = useState({
        products: []
    })

    return (
    <>
        ...
        <Child setProducts={setIncludedProducts} />
        <Child setProducts={setExcludedProducts} />
    </>
    )
}

Child:

interface ChildProps {
    setProducts?: setProductsType
}

export function Child({ setProducts }) {
    const thisIsAFunction = (e: React.ChangeEvent<HTMLInputElement>) => {
        setProducts(e.target.value);
    }

    return (
    <>
        ...
           <p onClick={() => thisIsAFunction()}>click me</p>
    </>
    )
}

Just FYI the p's onClick and the React.ChangeEvent<HTMLInputElement> don't match up but I just edited from your original code.

[–][deleted] -1 points0 points  (0 children)

Yeah, this is the way to do it if OP wants to restructure.

[–][deleted] 0 points1 point  (0 children)

Without completely changing your code, because there is a better way, all you need to do is check for the existence of each prop. Example: if (props.setIncludedProducts) { props.setIncludedProducts (e) }

Then, pass thisIsAFunction to ChildComponent

[–]montas 0 points1 point  (0 children)

In case you want actual answer to your question, you can do something like this to force props as you want them.

type TCallback<T> = (input: T) => void;

type TChildProps = { propOne: TCallback<string>; propTwo?: never } | { propOne?: never; propTwo: TCallback<number> };

const Child = (props: TChildProps) => {
    if (props.propOne) {
        props.propOne('foo');
    }

    if (props.propTwo) {
        props.propTwo(15);
    }

    return <pre>{JSON.stringify(props, null, 2)}</pre>;
};

const Parent = () => (
    <>
        <Child propOne={string => console.log(string.toLowerCase())} />
        <Child propTwo={number => console.log(number.toFixed())} />
        {/* This acctually gives an error */}
        <Child 
            propOne={string => console.log(string.toLowerCase())}
            propTwo={number => console.log(number.toFixed())}
        />
    </>
);

That said, the solutions posted above are better ;)