My quick implementing of a React screen with La Taverne

uralys

Uralys

Posted on February 12, 2024

My quick implementing of a React screen with La Taverne

Introduction

Previously in AI 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

0 - Goal

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

Image description

Now, let's see how I implemented this screen with React and La 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:.

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

const keysForPernaliltyTraits: Array<keyof PersonalityTraits> = Object.keys(
  personalityTraits
) as Array<keyof PersonalityTraits>;
Enter fullscreen mode Exit fullscreen mode

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

<>
  {keysForAdjectives.map((key: keyof ProjectAdjectives) => (
    <>
      {projectAdjectives[key].map(adjective => (
        <p
          key={adjective}
          label={adjective}
        />
      ))}
    </>
  ))}
</>
Enter fullscreen mode Exit fullscreen mode

(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 is a Redux + RTK alternative, based on ImmerJS: the idea is the same: dispatching actions and reducing a global app state.

With La 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 so I created a snippet to set actions and reducing quickly:

Image description

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

Image description

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

Image description

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

Here I realised I also needed to add these types:

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];
Enter fullscreen mode Exit fullscreen mode

Just a reminder to help you following the types:

Image description

And now I can type the payload:

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;
  }
};
Enter fullscreen mode Exit fullscreen mode

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

type ABChoices = SelectedProjectAdjectives & SelectedPersonalityTraits;

type State = {
  choices: ABChoices;
}

const initialState: State = {
  choices: {}
}
Enter fullscreen mode Exit fullscreen mode

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

export default {
  initialState,
  reactions: [
    onPickABChoice
  ]
}
Enter fullscreen mode Exit fullscreen mode

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:

import {useTaverne} from 'taverne/hooks';

// ...
// in the Component:

const {dispatch, pour} = useTaverne();
const choices = pour('user.choices');
Enter fullscreen mode Exit fullscreen mode

Let's write the onClick handler:

const selectAdjective =
  (key: keyof ProjectAdjectives, adjective: ProjectAdjective) => () => {
    dispatch({
      type: PICK_AB_CHOICE,
      payload: {key, choice: adjective}
    } as PickABChoiceAction);
  };
Enter fullscreen mode Exit fullscreen mode

And finally the view can be completed:

<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>
Enter fullscreen mode Exit fullscreen mode

4 - Testing the app

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

Image description

The state is updated when we click on a choice:

Image description

Here is the result again:

Image description

Conclusion

That's my React workflow with La Taverne, starting from google doc.

For next articles I plan to explain La 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!

đź’– đź’Ş đź™… đźš©
uralys
Uralys

Posted on February 12, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related