I was going through the react course on @FrontendMasters by @holtbt and I noticed how he used a custom hook to return a closure of react component, it's state object and the state modifier to create a reusable component.

When I want to create a component for rendering similar elements with different data I just go ahead a create a component which excepts the dynamic data as props.

Let's take an example where we want to create multiple dropdown elements with different options. I would go ahead and create a component something like this



// DropdownElement.js import React , { useState } from ' react ' ; const DropdownElement = props => { const { dropdownLabel , options } = props ; const [ selectedValue , updateSelectedValue ] = useState ( options [ 0 ]); return ( <> < label htmlFor = { dropdownLabel } > { dropdownLabel } </ label > < select id = { dropdownLabel } value = { selectedValue } onChange = { e => updateSelectedValue ( e . target . value ) } onBlur = { e => updateSelectedValue ( e . target . value ) } disabled = { ! options . length } > { options . map ( item => ( < option key = { item } value = { item } > { item } </ option > )) } </ select > </> ); }; export default DropdownElement ;

Now if we want to create any dropdown element, we can use <DropdownElement /> passing in props with it.

Let's say we want to create a filter component for shoes which has Color and Size dropdown fields.



//shoeFilter.js import React from ' react ' ; import DropdownElement from ' ./DropdownElement ' ; const ShoeFilter = () => ( <> < DropdownElement dropdownLabel = "Shoe Color" options = { [ " black " , " red " , " white " ] } /> < DropdownElement dropdownLabel = "Shoe Size" options = { [ " 6 " , " 7 " , " 8 " , " 9 " , " 10 " ] } /> </> ); export default ShoeFilter ;

This will create two dropdowns Shoe Color and Shoe Size . This is what people generally do, or at least this is what I do. There is nothing wrong with it. But, what if we could give the composite component <DropdownElement /> any name we want when we use it? Say for Shoe Color we could call it with <ShoeColorDropdown /> and for Shoe Size it could be <ShoeSizeDropdown /> This would certainly increase readability. So how can we do this?



import React , { useState } from ' react ' ; const useDropdown = ( dropdownLabel , options ) => { const [ selectedValue , updateSelectedValue ] = useState ( options [ 0 ]); const DropdownComponent () => ( <> < label htmlFor = { dropdownLabel } > { dropdownLabel } </ label > < select id = { dropdownLabel } value = { selectedValue } onChange = { e => updateSelectedValue ( e . target . value ) } onBlur = { e => updateSelectedValue ( e . target . value ) } disabled = { ! options . length } > { options . map ( item => ( < option key = { item } value = { item } > { item } </ option > )) } </ select > </> ); return DropdownComponent ; }; const ShoeFilter = () => { const ShoeColorDropdown = useDropdown ( " Shoe Color " , [ " black " , " red " , " white " ]); const ShoeSizeDropdown = useDropdown ( " Shoe Size " , [ " 6 " , " 7 " , " 8 " , " 9 " , " 10 " ]); return ( <> < ShoeColorDropdown /> < ShoeSizeDropdown /> </> ); };

So what is happening here is I am giving a name to the closure which is returned when useDropdown() is invoked and since that closure returns a react component we can go ahead and render it.

Now I have used this component just to render some data, we can extend this by returning an array of objects related to the component like its state and state modifier so the parent component can directly access the component data and maybe also change it. This is a custom hook and the next post will explain it well. I will update on twitter once it's out, please show me some love there :P

Let me know your thought's.