Is your React component not rendering?
Quick quiz: When a React component loads data from the server in
componentWillMount like this one below, what will it render?
If you answered “nothing” or “a console error,” congrats!
If you answered “the data I fetched,” keep reading ;)
State Starts Off Uninitialized
There are two important things to realize here:
- A component’s state (e.g.
this.state) begins life as
- When you fetch data asynchronously, the component will render at least once before that data is loaded – regardless of whether it’s fetched in the
Yes, even though
componentWillMount are called before the initial render, asynchronous calls made there will not block the component from rendering. You will still hit this problem.
This is easy to fix. The simplest way: initialize
state with reasonable default values in the constructor.
For the component above, it would look like this:
You could also handle the empty data inside
render, with something like this:
This is not the ideal way to handle it though. If you can provide a default value, do so.
The lack of default or “empty state” data can bite you another way, too: when undefined state is passed as a prop to a child component.
Expanding on that example above, let’s say we extracted the list into its own component:
See the problem? When
Quiz first renders,
this.state.items is undefined. Which, in turn, means
items as undefined, and you get an error –
Uncaught TypeError: Cannot read property 'map' of undefined in the console.
Debugging this would be easier if
propTypes set up, like this:
With this in place, you’ll get this helpful message in the console:
“Warning: Failed prop type: Required prop
items was not specified in
However, you will still get the error –
Uncaught TypeError: Cannot read property 'map' of undefined. A failed propType check does not prevent the component from rendering, it only warns.
But at least this way it’ll be easier to debug.
One more way to fix this: you can provide default values for props.
Default props aren’t always the best answer. Before you set up a default prop, ask yourself if it’s a band-aid fix.
Is the default value there just to prevent transient errors when the data is uninitialized? Better to initialize the data properly.
Is the prop truly optional? Does it make sense to render this component without that prop provided? Then a default makes sense.
This can be done a few ways.
This method works whether your component is a stateless functional one, or a class that inherits React.Component.
defaultProps static property
This method only works for classes, and only if your compiler is set up to support the static initializer syntax from ES7.
Destructuring in render
A default can be provided using the ES6 destructuring syntax right in the render function.
This line says “extract the
items key from
this.props, and if it’s undefined, set it to an empty array”.
Destructuring in arguments
If your component is of the stateless functional variety, you can destructure right in the arguments:
- Async calls during the component lifecycle means the component will render before that data is loaded, so…
statein the constructor and/or be sure to handle empty data.
- Use PropTypes to aid debugging
- Use default props when appropriate
- Destructuring syntax is a clean, easy way to provide defaults
This article has been translated into Korean here.
Learning React can be a struggle -- so many libraries and tools!
My advice? Ignore all of them :)
For a step-by-step approach, read my book Pure React.