My quick implementing of a React screen with La Taverne
Published: 2024-02-12 10:02:07

## Introduction

Previously in [AI](https://medium.com/@uralys/short-story-from-a-document-to-typed-code-with-ai-7643bc54a849) I explained how I got a JSON from a Google Doc, and how I used AI to accelerate defining my typings.

Today I have to display a Carousel of choices, from this `typescript` data:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/drx0bsvhfa1fjy4usgdq.png)

## 0 - Goal

To have in mind what I'll explain with code, let's see the final result immediately:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s2vaqjwdtln94e3o6kow.gif)

Now, let's see how I implemented this screen with React and [**La Taverne**](https://github.com/uralys/taverne).

## 1 - Mapping the choices with React

We need to ask the user to pick between choices for every adjective and trait.

Let's start by listing every keys:.

```ts
const keysForAdjectives: Array<keyof ProjectAdjectives> = Object.keys(
  projectAdjectives
) as Array<keyof ProjectAdjectives>;

const keysForPernaliltyTraits: Array<keyof PersonalityTraits> = Object.keys(
  personalityTraits
) as Array<keyof PersonalityTraits>;
```

Now, we can map over the keys to display both choices:

```ts
<>
  {keysForAdjectives.map((key: keyof ProjectAdjectives) => (
    <>
      {projectAdjectives[key].map(adjective => (
        <p
          key={adjective}
          label={adjective}
        />
      ))}
    </>
  ))}
</>
```

(Same goes for `keysForPernaliltyTraits`)

## 2 - Preparing the state with La Taverne

Before to add the `onClick` to select the choice, let's prepare the state where to store the selected choices.

[**La Taverne**](https://github.com/uralys/taverne) is a Redux + RTK alternative, based on ImmerJS: the idea is the same: dispatching actions and reducing a global app state.

With [**La Taverne**](https://github.com/uralys/taverne), the application state is split into feature sub states, called a **`barrel`**.

So I go to my `user.barrel.ts` and add a new action, the one we'll `dispatch` when the user will select a choice.

Copilot as not learned much about [**La Taverne**](https://github.com/uralys/taverne) so I created a snippet to set actions and reducing quickly:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n6lf2ugz4qhedounopar.png)

Thanks to 2 placehoders, I just need to choose a namespace and a `PascalCase` action name,

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/40y3a3mya16xul6mtx22.png)

Then 2 shortcuts later I have my action almost ready to use:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qy33i7wykhg2g5y3qq6q.png)

Let's type and use the `payload` in the reducer.

Here I realised I also needed to add these types:

```ts
export type ProjectAdjective =
  | AvantGardeOrClassic[number]
  | CreativeOrConventional[number]
  | ModernOrTraditional[number]
  | InnovativeOrProven[number]
  | MinimalisticOrElaborate[number]
  | FunOrSerious[number]
  | ElegantOrCasual[number]
  | BohemianOrUrban[number];

export type PersonalityTrait =
  | AdaptableOrStructured[number]
  | CollaborativeOrIndependent[number]
  | ProactiveOrReactive[number]
  | PerseveringOrFlexible[number]
  | ReservedOrExtraverted[number]
  | PassionateOrObjective[number]
  | PerfectionistOrEfficient[number]
  | PositiveOrRealistic[number];
```

Just a reminder to help you following the types:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b8vd4rsaxmsv7rshs9tq.png)

And now I can type the `payload`:

```ts
export const PICK_AB_CHOICE = '@@user/PICK_AB_CHOICE';

type PickABChoicePayload = {
  key: keyof ProjectAdjectives | keyof PersonalityTraits;
  choice: ProjectAdjective | PersonalityTrait;
};

export type PickABChoiceAction = {
  type: '@@user/PICK_AB_CHOICE';
  payload: PickABChoicePayload;
};

const onPickABChoice = {
  on: PICK_AB_CHOICE,
  reduce: (state: State, payload: PickABChoicePayload) => {
    const {key, choice} = payload;
    state.choices[key] = choice;
  }
};
```

So let's go up to my `State` to define `choices` properly:

```ts
type ABChoices = SelectedProjectAdjectives & SelectedPersonalityTraits;

type State = {
  choices: ABChoices;
}

const initialState: State = {
  choices: {}
}
```

Finally we add the reaction `onPickABChoice` to the list on my barrel's `reactions`:

```ts
export default {
  initialState,
  reactions: [
    onPickABChoice
  ]
}
```

Our app state is ready to handle the user's choices.

## 3 - Dispatching the action

Back to our React component, we can now add the `onClick` to dispatch the action.

First we need the `dispatch` function and the `pour` hook to read the state:

```ts
import {useTaverne} from 'taverne/hooks';

// ...
// in the Component:

const {dispatch, pour} = useTaverne();
const choices = pour('user.choices');
```

Let's write the `onClick` handler:

```ts
const selectAdjective =
  (key: keyof ProjectAdjectives, adjective: ProjectAdjective) => () => {
    dispatch({
      type: PICK_AB_CHOICE,
      payload: {key, choice: adjective}
    } as PickABChoiceAction);
  };
```

And finally the view can be completed:

```ts
<Carousel>
  {keysForAdjectives.map((key: keyof ProjectAdjectives) => (
    <React.Fragment key={key}>
      {projectAdjectives[key].map(adjective => (
        <CheckboxWithLabel
          key={adjective}
          selected={get(key, choices) === adjective}
          onClick={selectAdjectives(key, adjective)}
          label={t(`adjectives.${adjective}`)}
        />
      ))}
    </React.Fragment>
  ))}
</Carousel>
```

## 4 - Testing the app

Using Redux devtools, we can see the action triggered when we click on a choice:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3qjqu1kv6ngj493bindm.png)

The state is updated when we click on a choice:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ng6d0ndr2mxe5wa62otr.png)

Here is the result again:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s2vaqjwdtln94e3o6kow.gif)

## Conclusion

That's my React workflow with [**La Taverne**](https://github.com/uralys/taverne), starting from google doc.

For next articles I plan to explain [**La Taverne**](https://github.com/uralys/taverne) in simpler terms and examples,

Also I may explain how I created this Carousel with React and Styled Components, or just let me know what you'd want me to cover ?

Thanks for reading, see you around!