Practice of various React component communication methods

In React, communication between components is a very important topic. When we build complex applications, we often need different components to share data or collaborate with each other. React provides several ways to achieve cross-component communication. Below I will detail several of these communication methods and provide actual code examples.

Using React Context

A common use case for cross-component communication based on React Context is to create a context that can be shared and trigger behaviors between different components. The following is a simplified example that shows how to trigger methods in other components (for example, a popup component) in app.tsx.

1. Create a Context

First, we create a new Context. This Context will contain the methods we want to share across our application.

import React, { createContext, useContext } from 'react';

// Create Context 
const  MyContext = createContext ({
   togglePopup : () => {}, // This is an example method 
});

2. Create a Context Provider

Next, create a provider component that will make the values ​​in the Context accessible to different parts of the application.

export const MyProvider = ({ children }) => {
  const togglePopup = () => {
     // Here implements the display and hiding logic of the pop-up window 
    console . log ( "Toggle Popup called" );
  };

  return (
    <MyContext.Provider value={{ togglePopup }}>
      {children}
    </MyContext.Provider>
  );
};

3. Use Provider in app.tsx

In app.tsx, wrap the entire application with MyProvider so that any child component can access the values ​​in the Context.

import  React  from  'react' ;
 import { MyProvider } from  './MyProvider' ; // Import the Provider just created

function App() {
  return (
    <MyProvider>
      {/*The rest of the application*/}
    </MyProvider>
  );
}

export default App;

4. Use Context in child components

Finally, use this Context in the required components. For example, if you have a popup component, you can use this Context in it.

import React, { useContext } from 'react';
import { MyContext } from './MyContext';

const Popup = () => {
  const { togglePopup } = useContext(MyContext);

  return (
    <div>
      {/* Contents of the pop-up window*/}
      < button  onClick = {togglePopup} > Close pop-up window </ button > 
    </ div >
  );
};

export default Popup;

In this example we create a Context that can be shared throughout the application. We define a togglePopup method and use it through the Context in the required components. This approach makes cross-component communication simple and modular.

Use custom events

Using custom events for inter-component communication is a very flexible approach. In React, we can use third-party libraries such as mitt or eventemitter3 to implement this mechanism. Below is an implementation example based on this idea. The following is an example using mitt. mitt is a lightweight event emitter/listener library.

1.Install mitt

Use to npm install mittinstall an event listener, and then create an Event instance that will be shared throughout the application.

import my from  'my' ;

const emitter = mitt();

export default emitter;

2. Trigger events in app.tsx

In app.tsx, you can trigger a custom event that will be listened and responded to by other components.

import React from 'react';
import emitter from './emitter';

function App() {
   const  openPopup = () => {
    emitter.emit('togglePopup', true);
  };

  return (
     < div > 
      < button  onClick = {openPopup} > Open popup window </ button >
      {/* Other components*/}
    </div>
  );
}

export default App;

3. Listen to events in other components

In your public component (such as a popup component), listen to the events previously triggered in app.tsx.

import React, { useEffect, useState } from 'react';
import emitter from './emitter';

const Popup = () => {
  const [isOpen, setIsOpen] = useState(false);

  useEffect(() => {
    const toggleListener = (state) => {
      setIsOpen(state);
    };

    emitter.on('togglePopup', toggleListener);

    return () => {
      emitter.off('togglePopup', toggleListener);
    };
  }, []);

  if (!isOpen) return null;

  return (
    <div>
      {/* Pop-up window content*/}
      < button  onClick = {() => setIsOpen(false)}>Close pop-up window </ button > 
    </ div >
  );
};

export default Popup;

This example shows how to use mitt to implement cross-component communication. This approach is particularly useful for complex interactions that are not easily passed through props or state. It can also help you reduce your dependence on global state management solutions, thus keeping components more decoupled and reusable.

Using React Ref

Using React Ref to implement method calls between components is a direct and effective way, especially suitable for scenarios where parent components need to directly call methods in child components. Below is an example implemented using React Ref.

1. Create subcomponents and expose methods

First, create a child component and use useImperativeHandle and forwardRef to expose specific methods.

import React, { useImperativeHandle, forwardRef } from 'react';

const  Popup = forwardRef ( ( props, ref ) => {
   useImperativeHandle (ref, () => ({
     openPopup : () => {
       console . log ( "Pop-up window opens" );
       // Pop-up window opening logic
    },
    closePopup : () => {
       console . log ( "Pop-up window closed" );
       // Pop-up window closing logic
    }
  }));

  return (
     <div> Here is the content of the pop - up window </div>
  );
});

export default Popup;

2. Use Ref to call the method in the parent component

Next, create a ref in the parent component and pass it to the child component. Then, use this ref to call methods in the child component.

import React, { useRef } from 'react';
import Popup from './Popup';

function App() {
  const popupRef = useRef();

  const  openPopup = () => {
    popupRef.current.openPopup();
  };

  const closePopup = () => {
    popupRef.current.closePopup();
  };

  return (
     < div > 
      < button  onClick = {openPopup} > Open popup window </ button > 
      < button  onClick = {closePopup} > Close popup window </ button > 
      < Popup  ref = {popupRef} /> 
    </ div >
  );
}

export default App;

Using React Ref to call child components is a very intuitive and simple method, especially suitable for scenarios where you need to control the behavior of child components directly from the parent component. It allows the parent component to directly access the instance of the child component through ref

Use Redux to implement communication between components

Redux is a popular state management library for large React applications. With Redux, you can share state and logic between different parts of your application. The following is a simplified example showing how to use Redux to update and access application state.

1. Set up Redux

First, you need to set up the basic elements of Redux: stores, reducers, and actions.

// actions.js
export const togglePopup = () => ({
  type: 'TOGGLE_POPUP'
});

// reducer.js
const initialState = {
  isPopupOpen: false
};

export const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'TOGGLE_POPUP':
      return { ...state, isPopupOpen: !state.isPopupOpen };
    default:
      return state;
  }
};

// store.js
import { createStore } from 'redux';
import { reducer } from './reducer';

export const store = createStore(reducer);

2. Use Redux in app.tsx

Use Redux’s Provider to wrap your application and trigger actions through dispatch where needed.

import React from 'react';
import { Provider } from 'react-redux';
import { store } from './store';
import { togglePopup } from './actions';
import Popup from './Popup';

function App() {
  return (
    <Provider store={store}>
      <button onClick={() => store.dispatch(togglePopup())}>
        Switch pop-up window status
      </button>
      <Popup />
    </Provider>
  );
}

export default App;

3. Connect Redux in other components

Use the connect function (or useSelector and useDispatch hooks) in the required components to access and update Redux state.

import React from 'react';
import { connect } from 'react-redux';

const Popup = ({ isPopupOpen }) => {
  if (!isPopupOpen) return null;

  return (
     < div > Pop-up window content </ div >
  );
};

const mapStateToProps = state => ({
  isPopupOpen: state.isPopupOpen
});

export default connect(mapStateToProps)(Popup);

Redux provides a centralized store for managing the state of the entire application. This is very useful for large applications because it avoids repeated transfer of state between multiple components. Redux improves code maintainability and scalability by centralizing and modularizing logic . It has a wide range of middleware and ecosystem, supporting advanced functions such as asynchronous operations, logging, and persistence.

Use Callbacks to implement communication between components

Passing callback functions to child components through props is one of the most basic communication methods in React.

1. Define and pass Callback in the parent component

import React, { useState } from 'react';
import Popup from './Popup';

function App() {
   const [isPopupOpen, setIsPopupOpen] = useState ( false );

  const togglePopup = () => {
    setIsPopupOpen(!isPopupOpen);
  };

  return (
     < div > 
      < button  onClick = {togglePopup} > Toggle pop-up window state </ button > 
      < Popup  isOpen = {isPopupOpen}  onClose = {togglePopup} /> 
    </ div >
  );
}

export default App;

2. Use Callback in child components

import React from 'react';

const Popup = ({ isOpen, onClose }) => {
  if (!isOpen) return null;

  return (
    <div>
      Pop-up content
      <button onClick={onClose}>关闭</button>
    </div>
  );
};

export default Popup;

For simple parent-child component communication, using callback functions is straightforward and simple, and it avoids introducing additional libraries or complex architectures. To keep the component independent and reusable, because the child component does not need to care about how the state is managed, only how it responds to these callbacks.

Callback methods do not require any additional state management libraries or contexts, which makes applications more lightweight, reducing dependencies and introducing complexity. For small or less complex applications , using callbacks for state management is often sufficient and avoids over-design.

Summarize

In React, component communication is a key part of building dynamic and interactive user interfaces. React provides multiple ways to implement communication between components. This article lists several of these communication methods and provides code examples. Each method is suitable for different scenarios and needs. I hope this article can help you better understand and apply these technologies.