Kent C. Dodds - Advanced Patterns
Planted April 06, 2020
I’m over halfway through this masterclass on React with Kent. This has been a pretty deep dive and I’m finding my day-to-day development massively enriched by what I’ve learnt so far.
This time we’re looking at patterns in React. I’m used to patterns from PHP and Python but I don’t necessarily have a big awareness of them in React.
Some of these have names which are just used as reference and shouldn’t be seen as the name
of the pattern. Naming things helps people to talk about them but also can be used as weird gatekeeping mechanisms - “Oh, you’ve never heard of the blah-ba-blah pattern - such a newb!“.
Context Controller
When we export a derivative dispatch function from our context controllers, we end up causing ourselves extra work. You might create your own increment
and decrement
functions which call dispatch
. It becomes a major annoyance when you have a sequence of dispatch
functions that need to be called.
We might create helper functions and share them in the value object. Then we have to useCallback to wrap the functions so we can use the dependencies array properly.
An alternate approach is to export module level functions that are imported at that level rather than the context level. These take the dispatch as an argument which is passed from the context.
Then to use them, we get the dispatch like we normally do and then pass it to our module level functions.
This way if we don’t have to memoize the function and can pass any arguments into a dependency array.
Compound Components
This is used a lot by the Reach UI library. If you have components that themselves have nested components (think navbars and links, or forms and inputs) then you could initialise this component with a large and (potentially) unwieldly configuration object.
A better way, is to have the parent component use React.children.map()
to clone each of the children with React.cloneElement(child, { //additional props})
. For the example Kent used, each of the nested components needed the on
state and the toggle
function.
If you want to include DOM elements then you need to clone those without passing on the new props. In this case, you can test the child.prop type. If it is a string or not a function, clone without the extra props, otherwise add the props.
I’ve used this a bit in practice when adding a class to selected
components in a navigation.
Flexible Compound Components
Using the cloneElement approach for these compound components means we can only impact immediate children. If we want to be more flexible, we can use a context provider for our component and pass through the required elements that way.
When would you use the default value for createContext?
It would be good to provide a more helpful error to our context helper function.
Prop Collections and Getters
Rather than be specific about the exact elements you want to provide or making bespoke custom elements that need to be used, instead you can use a prop collection to be able to group together the relevant props.
This way, if the user wants to swap out the type of underlying components, they are free to do this as long as they use the props that your provide.
If you use a getProps function, then you can spread any extra props that the user wants to pass through as well.
That way you can deal with extra props:
This is used a lot in libraries like react-table
and downshift
.
State Reducer
It may be that you want to allow the user to completely override the behaviours of the component you are sharing. In this case, you can allow a custom reducer to be passed into our component.
and when you call you can pass in your own reducer:
or your user could just overwrite the methods they want to:
Good to have the types to be in objects to reduce the chance of typos.
Kent’s latest thinking on this
Control Props
Sometimes, people want to be able to manage the internal state of our component from the outside. The state reducer allows them to manage what state changes are made when a state change happens, but sometimes people may want to make state changes themselves. We can allow them to do this with a feature called “Control Props.”
This is pretty much the same as controlled input elements that you’ve probably done a million times in React.