Dynamic Name React Component With Closure
Tags: react, javascript, pattern
Published: 2020-03-17 09:32:15

I was going through the [react course](https://frontendmasters.com/courses/complete-react-v5/) on [@FrontendMasters](https://twitter.com/FrontendMasters) by [@holtbt](https://twitter.com/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
```jsx
// 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.
```jsx
//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?
```jsx
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](https://twitter.com/zlfnhmd) once it's out, please show me some love there :P

Let me know your thought's. 


<code>If anyone is getting started with react, [this course](https://frontendmasters.com/courses/complete-react-v5/) on [@FrontendMasters](https://twitter.com/FrontendMasters) by [@holtbt](https://twitter.com/holtbt) is a great starting point. I got the idea for this pattern from his lecture. Also, the subscription to Frontend Masters is really really worth it. The quality of content is just amazing. Kudos to [@1Marc](https://twitter.com/1Marc) for putting together an amazing platform.</code>