React Essentials
05 Pokebag

Pokebag

  • Display the bag of caught Pokemon on the right of the page
  • When the user correctly guesses the Pokemon, add it to the bag
  • Do not allow adding the same Pokemon more than once

Let's try some TDD!

What could be a simple test case to start with?

How about the empty bag?

TDD 1

                    
                        const component = render(...)

                        expect(
                            component.getByText('No Pokemons yet.')
                        ).not.toBeNull();
                    
                

...make it green!

TDD 2

Add some props to the component

                    
                        render(<PokeBag pokemons={['a', 'b']} />);
                    
                

Rendering a list

Remember, you can use regular JS inside JSX.

                    
                    <ul>
                        {pokemons.map(p => (
                            <li>{pokemon}</li>
                        ))}
                    </ul>
                    
                

Check out the console

Virtual DOM & Reconciliation

or simply change detection (CD)

Diffing two trees

This is an O(n3) algorithm, which is not suitable for web applications.

React uses heuristics to make it an O(n) algorithm.

Details

Keys

The heuristic relevant for us is the key attribute.

It lets React know if an element is still the same or not.

                    
                    <ul>
                        {pokemons.map(p => (
                            <li key={pokemon}>{pokemon}</li>
                        ))}
                    </ul>
                    
                

Wiring up

Add the new (and tested) pokebag component to the App and add Pokemons to it on a correct guess.

Where do we need to put the state containing the Pokemon?

PokeBagList

The PokeBag component doesn't look very nice. Let's extract a component for the List.

                    
                    <h3>Poke Bag</h3>
                    <PokeBagList pokemons={pokemons} />
                    
                

Prop drilling

Introducing the Context API

Context provides a way to pass data through the component tree without having to pass props down manually at every level.

Defining the Context

App.tsx

                    
                    const PokeBagContext = React.createContext({
                      pokemons: [],
                      addPokemon: () => {},
                    });
                    
                

Context Provider

Wrap your component in App.tsx

                    
                    <PokeBagContext.Provider
                      value={{
                        pokemons: ...,
                      }}
                    >
                        ...
                    </PokeBagContext.Provider>
                    
                

The useContext hook

                    
                    const { pokemons } = useContext(PokeBagContext);
                    
                

We now no longer need to keep passing props to the components.

This is a rather "simulated" use case passing the pokebag as props would be perfectly fine.

Where to use Context?

  • View config, e.g. theme settings
  • Logged in user
  • Form state

Caveats of Context

  • A little more awkward to test
  • Less explicit - you need to search where the data is coming from

Questions?