Passing Data Between Components in React
For the last several years, React has been undoubtedly the leading UI library for building user interfaces. So much so that it inspired supporting libraries and frameworks of its own, such as Next.js to build full-stack applications, utilize server-side rendering, SSGs, and more.
Building even remotely successful web application requires a thorough understanding of component trees. Communication between components is especially important, especially because some components might hold the data other components need.
In this blog post, I want to explain props as a way to share data in component trees in React.
Understanding Components in React
Components are foundational feature to React. They help us encapsulate certain feature or small visual piece of UI and reuse them throughout the application.
Every small component renders a small part of the application, for performing dynamic features, or both. React web applications are nothing but component trees where these components are combined to achieve a unified result.
In general, it's a good practice to make components as small as possible. Then mix and combine them into bigger components. Then a certain page might have multiple of these components. Thus, you have a component tree with multiple branches. Small components are good because they can use props to create a friendly interface for easy combination of props.
Before we delve into props, it's important to understand relationships between React components. Components can have parent-child relationships with other components. Some child components might have children of their own, thus they are parent components.
Child components accept props to customize their appearance, functionality, and content. Parent components pass down data via props and thus control children components.
Data Transfer via Props
In React, there are a number of ways to pass data from parent to children. Props is the simplest and most commonly used method for doing so. Props are always passed down from parent components to the children components. Or a 'grandparent' component might pass down data to its child that itself passes it down even further down the component tree. In this case, we get into the practice that is called 'prop drilling', the main difficulty with using props in React.
Children can not pass props to their parents, but child components can call the parent component's event handler passed down to them and update values in the state. This is an interesting practice which we'll discuss later.
Props and Immutability
Beginner React developers must remember several rules about the library. One rule is to never directly update the state. Another is that props are immutable. In other words, child components can not change data passed down to them from their parents.
This rule is important to follow because it helps maintain single source of truth and consistency of data throughout the app. Think of child components as functions that accept the argument. A function shouldn't change its own argument, but do a calculation (or perform a side effect) based on said argument.
Trying to change data passed down to components defeats their purpose, which is why React doesn't allow it.
Passing Data Among Siblings
In some cases, you need to pass data from one child component to another child of the same parent (often called sibling components). This is a difficult case, because props can only be passed down from parent to children. However, React offers some workarounds to do this. Specifically, child components can receive event handlers via props, and call these functions to update parent's state. This is a common practice to handle input change in React.
Then parent components can pass down data to whichever child components requires it. Once you get used to it, this is easier to do than you might think.
The Context API
Props have wide-reaching use cases, and they are flexible enough to be useful in many cases. However, when props are not enough, React offers an even more robust alternative - Context API. Context also solves the problem of component drilling - having to pass down data via props on multiple levels. Instead, context makes data available in a totally different space. Then other components (whether they are siblings or child components) can directly access this data.
In a way, context is like an enclosed namespace for storing important application data. When a child component needs it, they can access web app data regardless of their position in the component tree.
Sharing State Between Components
Unlike props, a component state contains data that is supposed to change. For example, users input values or external data received from the API. State is foundational to reactivity features of React, because the library is centered around the fact that it performs a re-render when state values change.
If multiple child components require access to data stored in the state, we need to create a structure where all child components share the same parent that stores said data. One parent maintains all data in the state, and passes it down to child component. This principle, called 'single source of truth', ensures consistency of data passed down via props.
Side effects in React
Performing side effects is an important aspect of building interactive UIs with React. If you want to perform a side effect only once, then you need useEffect without dependencies.
Use of Callback Functions
A common pattern is to use props to pass down data from parents to children. However, what happens when parent components needs to receive 'updates' from children components? The solution is simple - create a callback function, pass it down via props to child components, and call functions down on the component tree.
Even if called from within the child component, callback functions can still update state in the parent component. In a way, this violates the rule of uni-directional data flow, but it's a common practice in React, because child components do not directly pass data to their parents.
Understanding props is the key to understanding React. The library is based on reusable components, and communication between components is crucial for building interactive web applications in React.