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:
0 - Goal
To have in mind what I'll explain with code, let's see the final result immediately:
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>;
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}
/>
))}
</>
))}
</>
(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:
Thanks to 2 placehoders, I just need to choose a namespace and a PascalCase
action name,
Then 2 shortcuts later I have my action almost ready to use:
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];
Just a reminder to help you following the types:
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;
}
};
So let's go up to my State
to define choices
properly:
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
:
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:
import {useTaverne} from 'taverne/hooks';
// ...
// in the Component:
const {dispatch, pour} = useTaverne();
const choices = pour('user.choices');
Let's write the onClick
handler:
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:
<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:
The state is updated when we click on a choice:
Here is the result again:
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!
Top comments (0)