React - Closure that dependency!
Whats the difference between a custom hook and a functional component?
The (common) problem
You have a component and need to control its state, and it works great:
function BaseExample() { const [option, setOption] = useState('two'); const handleChange = (el) => { setOption(el.target.value); }; return ( <div> <select onChange={handleChange} value={option} > {[ { value: 'one', label: 'One' }, { value: 'two', label: 'Two' }, { value: 'three', label: 'Three' }, ].map((option) => ( <option key={option.value} value={option.value} > {option.label} </option> ))} </select> <div>{option ? `Selected: ${option}` : 'No selection'}</div> </div> );}
But what happens when you try to refactor it?
function RefactoredExample() { const [option, setOption] = useState('two'); const handleChange = (el) => { setOption(el.target.value); }; return ( <div> {SelectComponent(handleChange, option)} <div>{option ? `Selected: ${option}` : 'No selection'}</div> </div> );}function SelectComponent(handleChange, option) { return ( <select onChange={handleChange} value={option} > {[ { value: 'one', label: 'One' }, { value: 'two', label: 'Two' }, { value: 'three', label: 'Three' }, ].map((option) => ( <option key={option.value} value={option.value} > {option.label} </option> ))} </select> );}
Now, we have one component that has to know too much and another one that cant do anything on its own.
Enter custom hooks
By convention normal functional components return JSX and custom hooks can return anything.
Anything? Yes, even JSX.
function RefactoredWithHookExample() { const { option, SelectComponent } = useSelectComponent(); return ( <div> <SelectComponent /> <div>{option ? `Selected: ${option}` : 'No selection'}</div> </div> );}function useSelectComponent() { const [option, setOption] = useState('two'); const handleChange = (el) => { setOption(el.target.value); }; const SelectComponent = () => ( <select onChange={handleChange} value={option} > {[ { value: 'one', label: 'One' }, { value: 'two', label: 'Two' }, { value: 'three', label: 'Three' }, ].map((option) => ( <option key={option.value} value={option.value} > {option.label} </option> ))} </select> ); return { option, SelectComponent };}
Now the SelectComponent knows all it needs to control its state and the parent component knows only what it needs.
Anything goes with closures!
An example like this is hardly exciting, but remember that you can return anything from a hook!
Not only that, this can work as a closure, so you could have something like this:
function RefactoredWithClosureHookExample() { const { option, SelectComponent } = useSelectComponent({ options: [ { value: 'one', label: 'One' }, { value: 'two', label: 'Two' }, { value: 'three', label: 'Three' }, ], initial: 'two', }); return ( <div> <SelectComponent selectProps={{ style: { color: 'red' } }} optionProps={{ style: { color: 'green' } }} /> <div>{option ? `Selected: ${option}` : 'No selection'}</div> </div> );}function useSelectComponent({ options, initial }) { const [option, setOption] = useState(initial); const handleChange = (el) => { setOption(el.target.value); }; const SelectComponent = ({ selectProps, optionProps }) => ( <select onChange={handleChange} value={option} {...selectProps} > {options.map((option) => ( <option key={option.value} value={option.value} {...optionProps} > {option.label} </option> ))} </select> ); return { option, SelectComponent };}
This was, of course, an exaggeration. But by understanding whats possible youll be sure to find easier solutions to your problems.
Cover Photo by Jamie Matocios on Unsplash
Original Link: https://dev.to/noriller/react-closure-that-dependency-a50
Dev To
An online community for sharing and discovering great ideas, having debates, and making friendsMore About this Source Visit Dev To