Communicating between components in React
includes communication between parent and child components, sibling components, components separated by generations, and non-nested components.
Props
are used for communication between parent and child components. Props
can efficiently facilitate communication between parent and child components in a unidirectional data flow. Unidirectional data flow means that data can only flow from the parent component to the child component through props
, and the child component cannot modify the data passed through props
to change the corresponding state of the parent component. All props
create a unidirectional downward binding between parent and child props
. Updates to the parent props
will flow down to the child components, but the reverse is not true. This prevents accidental changes in the state of the parent component from the child component, making it difficult to understand the flow of data and increasing the difficulty of project maintenance. In fact, if a basic data type is passed to the child component and the value is modified in the child component, React
will throw an exception. If an object of a reference type is passed to the child component, modifying it in the child component will not prompt any message. However, both of these cases involve changing the unidirectional flow of data between parent and child components, which does not adhere to a maintainable design approach.
We often need to change the values of the parent component. For this, we can customize a logic in the parent component to handle receiving state changes, and then trigger the parent component's logical processing event when the relevant state changes in the child component. In React
, props
can accept any input. At this point, we pass a function through props
in the child component to trigger and pass the value to the parent component's instance for modifying the parent component's state
.
React Context
is suitable for communication between parent and child components as well as components separated by generations. React Context
provides a way to pass data between components in the component tree without manually adding props
at each layer. In a React
application, data is passed from top to bottom, i.e., from parent to child, through the props
attribute. However, for some types of attributes, this approach is extremely cumbersome. These attributes are required by many components in the application. Context
provides a way to share such values between components without explicitly passing props
through the component tree. In fact, React-Router
uses this method to pass data, which explains why <Router>
is outside all <Route>
s.
Using Context
is for sharing data that is global for a component tree. Simply put, in the parent component, data is provided through Provider
, and then in the child components, the data defined in Provider
is obtained through Consumer
. Regardless of how deep the child component is, as long as Provider
is used, the data provided in Provider
can be obtained, instead of being limited to obtaining data from the props
attribute of the current parent component. As long as the data defined in the parent component is in Provider
, child components can access it. Of course, if you just want to avoid passing props
layer by layer and the number of layers is not large, you can consider making a shallow copy of props
, deleting the props
that are no longer used in the subsequent components, and then using the spread operator, i.e., {...handledProps}
, to spread them for transmission, achieving a similar operation to the API
of Vue
's $attrs
and $listeners
.
Refs
are suitable for communication between parent and child components. They provide a way to access DOM
nodes or React
elements created in the render
method. In a typical React
data flow, props
are the only way for a parent component to interact with a child component. To modify a child component, you need to use new props
to re-render it. However, in some cases, it's necessary to forcefully modify a child component outside the typical data flow. The modified child component can be an instance of a React
component or a DOM
element. When rendering a component, it returns the component instance, while rendering a DOM
element, it returns the specific DOM
node. The ref
property provided by React
represents a reference to the actual instance of the component, which is essentially the component instance returned by ReactDOM.render()
. Additionally, it's important to avoid using refs
for anything that can be achieved declaratively. Usually, if it can be accomplished using props
and state
, it's best to avoid relying on refs
.
The EventBus
can be used for component communication in any situation. In the case of small-scale projects, you can completely use the central event bus EventBus
. It can perfectly solve communication between parent and child components, sibling components, and components that are not directly connected. In fact, it is an observer pattern. The observer pattern establishes a dependency relationship between objects, so when one object changes, it automatically notifies other objects, and they respond accordingly. Therefore, the object that changes is called the subject, while the notified object is called the observer. A subject can correspond to multiple observers, and these observers are not connected to each other. They can be added and removed as needed, making the system more easily extendable. First, we need to implement a publish-subscribe class to be exported as a singleton module. Each required component then imports it. Of course, it can also be used as a static cross-cutting concern mixin or use the event
library. In addition, it is essential to unsubscribe from event calls when the component is destroyed, otherwise it will cause memory leaks.
Redux
can also be used for inter-component communication in any scenario. Redux
introduces a single data source Store
to store state data. All components can modify the Store
through Action
and can also retrieve the latest state from the Store
. By using redux
, you can solve the shared state management of multiple components and communication between components.