Dynamic Item Selection: Made with React Hooks
Tags: beginners, webdev, react, html
Published: 2022-01-12 04:15:05

## TLTR

Jump to **Quick Explanation** below to get a 15 second explanation.

Just want to see it in action? Try out the [deployed demo](https://dynamic-item-selection.netlify.app/). Want a deep dive? Take a peek at [the repo](https://github.com/ec-rilo/dynamic-nav-menu-items).


## Requirements
You're required to know the below in order to understand what I'm going to be explaining in this article:

- React Hooks
- React Functional Components
- Styled-Components

Understand the above? Great, keep reading! If you don't I'd do some quick googling to learn about them or for a refresher.


## Quick Explanation

This Hook allows the user to create an 'n' number of list items that on hover will emphasize the hovered list item and dim all other elements.

When the user no longer is hovering over a list item all elements will return to the default coleration.

This hook also pairs with a styled component, in this case it's called TextAnimateLi which is hard coded to fit my styling needs but can be changed to your style and element preference.

## useTextAnimate
``` javascript
const useTextAnimate = (data) => {
  const [content, setContent] = useState(data);

  const setOneActive = (name) => {
    let contentCopy = [...content];

    contentCopy.forEach((item, index, arr) => {
      if (arr[index].name !== name) {
        arr[index].isActive = false;
      }
    });

    setContent(contentCopy);
  };

  const setAllActive = () => {
    let contentCopy = [...content];

    contentCopy.forEach((item, index, arr) => {
      arr[index].isActive = true;
    });

    setContent(contentCopy);
  };

  return { setOneActive, setAllActive, content };
};
```

This hook when used takes in an array of objects as it's argument.

``` javascript
const data = useTextAnimate([
    { name: 'work', isActive: true },
    { name: 'about', isActive: true },
]);
```

From here, we're assigning the array of objects `data` to `content` in state. This allows us to use stateful logic needed for dynamic style changing.

Then we come onto our first function `setOneActive` which will set all elements but the one with the matching name to false. This is the logic that allows us to see one element as emphasized.

The following function `setAllActive()` will set all items to be emphasized which is the default logic.

what is returned is:
- `content` - array of objects that the user provided.
- `setOneActive` - function
- `setAllActive` - function

## Real Life use

When using the hook it will take in an array of objects as an argument.

Each object must contain the following properties

- name (Init with the text you want in the list item)
- isActive (set it to true by default always)

``` javascript
const data = useTextAnimate([
    { name: 'work', isActive: true },
    { name: 'about', isActive: true },
    { name: 'contact', isActive: true },
    { name: 'cv', isActive: true },
  ]);
```
Note: the value retrieved from useTextAnimate must be assigned to a variable.

useTextContent will return 3 things.
- content (the array of objects from earlier)
- setOneActive (Explained in useTextAnimate above)
- setAllActive (Explained in useTextAnimate above)

The hook provided the logic needed now we are going to populate a unordered list with list items that will use that logic.

Before we start using the logic we are going to need the styled-component TextAnimateLi.

``` javascript
const TextAnimateLi = styled.li`
  color: white;
  transition: color 0.2s;
  cursor: pointer;
  ${({ content, index }) => {
    if (content[index].isActive === false) {
      return `
      color: rgba(255, 255, 255, 0.5);  
    `;
    }
  }}
`;

```

To keep it short and sweet. It uses data provided by useTextAnimate to style each list item dynamically.

Now in order to put this together, we need to map over the array we created in my example, we can do this with `data.content` (Remember, using the variable name `data` was a personal choice when creating the variable earlier. It can be anything you'd like!)

``` javascript
<ul className={className}>
      {data.content.map((item, index) => {
        return (
          <TextAnimateLi
            key={index}
            onMouseEnter={() => data.setOneActive(item.name)}
            onMouseLeave={() => data.setAllActive()}
            content={data.content}
            index={index}
          >
            {item.name}
          </TextAnimateLi>
        );
      })}
    </ul>
```

What's going on here? The parameter `item` in the arrow function is the current object within the array content.

For each Component TextAnimateLi we are adding a set of properties.
- `key`
MUST take index as it's value, do NOT use something like uniqid()).

- `onMouseEnter`
Calls the function `setOneActive()`

- `onMouseLeave`
Calls the function `setAllActive()`

- `content`
takes in the array of objects

- `index`
Takes the current index

Let's take a look back at TextAnimateLi to understand the styling logic.

``` javascript
/* It doesn't have to be a li. But for this case it's the best option. */
const TextAnimateLi = styled.li`
  /* This is the default color */
  /* You can set a new color here */
  color: white;
  transition: color 0.2s;
  cursor: pointer;
  ${({ content, index }) => {
    if (content[index].isActive === false) {
      return `
      /* This is the dimming color */
      /* You can set a new color here */
      color: rgba(255, 255, 255, 0.5);  
    `;
    }
  }}
`;
```

Pretty straight forward, when the current item is not active it will return a color which is dimmed otherwise, it will return to it's default color.

Take a look at my comments in the code to make changes as you see fit. feel free to mess around with the styling for different looks!

Enjoy!