The Basics
Components
React is a component library. It enables the dev to create reusable React Components. There are the following two types of components in React:
- Stateful Components
- Stateless Components
Also, you can write components in the following two ways:
- Class
- Function
The golden rule is to use primarily functional stateless components. They are easy to test and lightweight. If you need a state, then go with functional stateful components. This is possible since React 16.8 where React Hooks got introduced.
Unidirectional Data Flow
In contrast to Angular, React insists on one-way binding or one-way data flow. That means that data has only one way
of being transferred, namely from parent to child or from top to bottom. To make sure that a child can never update
what is being passed from the top (that are props
), it has been made read-only. So props
are immutable.
So the parent has a mutable state
which gets passed to the child as immutable props
. And when the child wants
to change the data at hand it can only do so via a callback function, which again must be passed from the parent
to the child as a property.
For more information read this article.
Props
In React you can pass (external) data from a parent component to a child component via a props
(properties) object.
The parent component renders the following Person
-Component and passes the following data:
<Person name="Tom" age="40" />
The Person
-Component then access the properties via the props
object as so props.name
.
When possible use props over state, because you create a dumb component that just needs to render the given input and does not have to care about state management. This is important, as most of the frontend bugs are due to poor state management.
Of course, one cannot build a sophisticated web application without having to hold and manage some kind of state.
State
When a component needs to keep track of information between renderings the component needs to manage this information aka state. State is "private" information and fully controlled by the component, meaning the component must update it on its own as it may change over time due to user interaction.
Depending on the type of component you choose (class vs function) you have to different mechanism to manage that state. As functional components are the de-facto standard now, I'll refer to them when speaking about components.
A (functional) component can manage state in different ways:
useState
: Manage a primitive value (preferred way) or object (maybe useuseReduder
or split into multipleuseState
-units)useReducer
: Use a reducer (function) and actions to manage state updatesuseRef
: Update internal state that must not be reflected to the user, e.g. timer or element-ids (a change here will not cause re-rendering)useContext
: To manage special state that is rarely changing and needed by multiple components across the app (e.g. active user or theme)useEffect
: To load component state e.g. via an http-call to the server
If state is needed by multiple components, then it should either be pulled to the closest shared parent. And if that is too cumbersome, then one can use the Context API.