Forget about controlled/uncontrolled components!

Shukant Pal
Jun 17 · 4 min read

You shouldn’t force your consumer to pass all those props! It’s unfair!

Yesterday, I found myself unwilling to implement another React component — a special slider that accepts multiple points. I found Gaëtan Renaudeau’s multi-slider to the simplest and fastest solution for my needs.

Before installing it though, I performed a quick source code inspection on this library. After sifting through several lines, I stopped here:

Multi-slider uses the library; and why not, it eliminates a lot of boilerplate for maintainers and consumers. is built as a fully controlled component; however, on wrapping it with , the consumer can use it as either controlled or uncontrolled. The logic to make it uncontrollable is hidden away.

MultiSlider example: http://greweb.me/multi-slider/

Crafting components with uncontrollable in mind

React components are built with mainly two types of props in mind — control-params and handlers. In the case of controlled components, rendering is purely based off of the control-params; when the user interacts with the component, the handler receives the updated ‘params’, which can be set in the new props.

For example, needs two props: and .

  • specifies the relative offsets at which the handles are on the slider’s track.
  • receives the new when the user drags a point.

The code snippet above resembles how would be built as a fully controlled component; however, its parent is forced to store in its own state. This is fine for one control-params/handler pair, but building the boilerplate for several pairs is not.

The parent is required to minimally provide the logic to store and update in its own state.

This may be undesirable when the consumer wants to only provide the initial offsets for .

In addition, consumers may want to control only certain features of the component. For example, a drop-down list might have two control-params: and , which are modified by and . Most consumers would leave the drop-down to open/close on its own and wouldn’t care to store in their own state. They are mainly concerned about the list of being displayed by the drop-down.

To provide such flexibility on our own, we will have to store each control-param in our own state and lift them to the parent only if the corresponding handler exists. For example, will store in its state too, unless the parent provides the callback.

This code snippet is twice as large as the previous one. It takes care of three more things:

  • copying or into the initial state.
  • calling only if it exists; otherwise, setting the state with the new values instead.
  • synchronizing new props into the state (in the controlled case)

You don’t have to waste time writing all this boilerplate — leave that to uncontrollable!

The uncontrollable wrapper

Uncontrollable requires you to just write the controlled version of your component. After that, you just wrap it with the function.

Definition of uncontrollable from npmjs.com

Uncontrollable with function components

can be used in your functional component without having to wrap it using .

Definition of useUncontrolled from npmjs.com

Check out the library right now — https://www.npmjs.com/package/uncontrollable.


The Startup

Medium's largest active publication, followed by +477K people. Follow to join our community.

Shukant Pal

Written by

Professional student freelancer

The Startup

Medium's largest active publication, followed by +477K people. Follow to join our community.