Sharing Variables Between Components in ReactJS

Avatar

By squashlabs, Last Updated: Dec. 20, 2023

Sharing Variables Between Components in ReactJS

Sharing Data Between Parent and Child Components in React

In React, data can be shared between a parent component and its child components through the use of props. Props allow data to be passed down from a parent component to its child components, enabling communication and data transfer.

Related Article: How to Build Forms in React

Passing Data from Parent to Child Components

To pass data from a parent component to its child components, you can use props. Props are passed as attributes when rendering the child component.

Here's an example of passing data from a parent component to its child component:

import React from 'react';

function ChildComponent(props) {
  return <p>Hello, {props.name}!</p>;
}

function ParentComponent() {
  const name = 'John';

  return <ChildComponent name={name} />;
}

In this example, the ParentComponent passes the name prop to the ChildComponent by including it as an attribute when rendering the ChildComponent. The ChildComponent receives the prop and uses it to display a greeting message.

Passing Data from Child to Parent Components

To pass data from a child component to its parent component, you can define a callback function in the parent component and pass it as a prop to the child component. The child component can then call the callback function and pass data back to the parent component.

Here's an example of passing data from a child component to its parent component:

import React, { useState } from 'react';

function ChildComponent({ onButtonClick }) {
  const handleClick = () => {
    onButtonClick('Button clicked');
  };

  return <button onClick={handleClick}>Click me</button>;
}

function ParentComponent() {
  const [message, setMessage] = useState('');

  const handleButtonClick = message => {
    setMessage(message);
  };

  return (
    <div>
      <ChildComponent onButtonClick={handleButtonClick} />
      <p>{message}</p>
    </div>
  );
}

In this example, the ChildComponent receives the onButtonClick prop, which is a callback function defined in the ParentComponent. When the button in the ChildComponent is clicked, the handleClick function is called, which in turn calls the onButtonClick callback function with the message "Button clicked". The ParentComponent updates the message state with the passed message and displays it in a paragraph element.

Difference Between Props and State in React

In React, both props and state are used to manage and pass data to components, but they have different purposes and characteristics.

Related Article: Implementing HTML Templates in ReactJS

Props

Props, short for properties, are a way to pass data from a parent component to its child components. Props are read-only and cannot be modified by the child components. They are typically used to customize the behavior or appearance of a component.

Here's an example of using props in a React component:

import React from 'react';

function Greeting(props) {
  return <p>Hello, {props.name}!</p>;
}

function App() {
  return <Greeting name="John" />;
}

In this example, the Greeting component receives a name prop and displays a greeting message with the name. The App component renders the Greeting component and passes the name prop with the value "John".

State

State is used to manage data that can change over time within a component. State is mutable and can be updated using the setState method or the useState hook in functional components. State is typically local to a component and not shared with other components unless explicitly passed as props.

Here's an example of using state in a React component:

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>{count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
}

In this example, the Counter component uses the useState hook to add state to the component. It initializes the count state to 0 and defines an increment function that updates the count state by incrementing it. The current count value is displayed in a paragraph element, and clicking the button triggers the increment function.

Sharing Data Between Sibling Components in React

In React, sharing data between sibling components can be achieved by lifting the state up to a common ancestor component. By managing the shared data in a parent component, it can be passed as props to the sibling components, enabling them to access and modify the shared data.

Lifting State Up

To share data between sibling components in React, you can lift the state up to a common ancestor component. This means that the shared data is managed and stored in a parent component, which then passes it as props to the sibling components.

Here's an example of sharing data between sibling components:

import React, { useState } from 'react';

function SiblingComponentA({ count, increment }) {
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
}

function SiblingComponentB({ count }) {
  return <p>Count: {count}</p>;
}

function ParentComponent() {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <SiblingComponentA count={count} increment={increment} />
      <SiblingComponentB count={count} />
    </div>
  );
}

In this example, the ParentComponent manages the count state and passes it as props to SiblingComponentA and SiblingComponentB. SiblingComponentA displays the count value and a button to increment it, while SiblingComponentB only displays the count value. When the button is clicked, the increment function is called, updating the count state in the ParentComponent, and causing both sibling components to re-render with the updated count value.

Related Article: How to Add If Statements in a ReactJS Render Method

The Purpose of Context in React

Context in React allows data to be passed through the component tree without explicitly passing props at every level. It provides a way to share data that needs to be accessed by multiple components at different levels of the component hierarchy.

Use Cases for Context

Context is useful in the following scenarios:

- Theme or styling information that needs to be accessed by multiple components.

- User authentication status or user information that needs to be accessed by multiple components.

- Localization information that needs to be accessed by multiple components.

- Global state management without using a state management library like Redux.

Creating a Context

To create a context in React, you can use the createContext function from the react package.

Here's an example of creating a context:

import React from 'react';

const MyContext = React.createContext();

In this example, the createContext function is used to create a context called MyContext. This context can now be used to share data between components.

Providing and Consuming a Context

To provide data to components that consume a context, you can wrap the components with a Provider component and pass the data as a value prop.

Here's an example of providing and consuming a context:

import React from 'react';

const MyContext = React.createContext();

function ParentComponent() {
  return (
    <MyContext.Provider value="Hello from context!">
      <ChildComponent />
    </MyContext.Provider>
  );
}

function ChildComponent() {
  const value = React.useContext(MyContext);

  return <p>{value}</p>;
}

In this example, the ParentComponent provides the value "Hello from context!" to the ChildComponent by wrapping it with a Provider component and passing the value as the value prop. The ChildComponent consumes the context using the useContext hook and displays the value in a paragraph element.

Related Article: Displaying Arrays with Onclick Events in ReactJS

Managing Global State in React

Managing global state in React involves storing and managing data that needs to be accessed and modified by multiple components throughout the component tree. There are various approaches and libraries available for managing global state in React, such as Redux, MobX, and Context API.

Using Redux for Global State Management

Redux is a popular state management library for React applications. It provides a centralized store that holds the application state and allows components to access and update the state using actions and reducers.

Here's an example of using Redux for global state management:

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

// Reducer function
function counterReducer(state = 0, action) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    case 'DECREMENT':
      return state - 1;
    default:
      return state;
  }
}

// Create the store
const store = createStore(counterReducer);

export default store;

// App.js
import React from 'react';
import { Provider } from 'react-redux';
import store from './store';
import Counter from './Counter';

function App() {
  return (
    <Provider store={store}>
      <Counter />
    </Provider>
  );
}

export default App;

// Counter.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';

function Counter() {
  const count = useSelector(state => state);
  const dispatch = useDispatch();

  const increment = () => {
    dispatch({ type: 'INCREMENT' });
  };

  const decrement = () => {
    dispatch({ type: 'DECREMENT' });
  };

  return (
    <div>
      <p>{count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
}

export default Counter;

In this example, we define a Redux store in a separate file called store.js. The store holds the application state and uses a reducer function to handle state updates. The App component wraps the Counter component with a Provider component from the react-redux package, which provides the Redux store to all components in the application. The Counter component uses the useSelector and useDispatch hooks to access the state and dispatch actions, respectively.

React provides various state management options, each with its own pros and cons. Some popular state management libraries in React include Redux, MobX, and Zustand.

Redux

Redux is a predictable state container for JavaScript applications. It provides a centralized store that holds the application state and allows components to access and update the state using actions and reducers. Redux follows the principles of immutability and unidirectional data flow.

Here's an example of using Redux for state management in React:

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

// Reducer function
function counterReducer(state = 0, action) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    case 'DECREMENT':
      return state - 1;
    default:
      return state;
  }
}

// Create the store
const store = createStore(counterReducer);

export default store;

// App.js
import React from 'react';
import { Provider } from 'react-redux';
import store from './store';
import Counter from './Counter';

function App() {
  return (
    <Provider store={store}>
      <Counter />
    </Provider>
  );
}

export default App;

// Counter.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';

function Counter() {
  const count = useSelector(state => state);
  const dispatch = useDispatch();

  const increment = () => {
    dispatch({ type: 'INCREMENT' });
  };

  const decrement = () => {
    dispatch({ type: 'DECREMENT' });
  };

  return (
    <div>
      <p>{count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
}

export default Counter;

In this example, we define a Redux store in a separate file called store.js. The store holds the application state and uses a reducer function to handle state updates. The App component wraps the Counter component with a Provider component from the react-redux package, which provides the Redux store to all components in the application. The Counter component uses the useSelector and useDispatch hooks to access the state and dispatch actions, respectively.

Related Article: How to Set Up Your First ReactJS Project

MobX

MobX is a simple and scalable state management library that uses observable objects to automatically track and update state. It provides a reactive programming model, where changes to observables are automatically propagated to the dependent components.

Here's an example of using MobX for state management in React:

// store.js
import { makeAutoObservable } from 'mobx';

class CounterStore {
  count = 0;

  constructor() {
    makeAutoObservable(this);
  }

  increment() {
    this.count++;
  }

  decrement() {
    this.count--;
  }
}

const counterStore = new CounterStore();

export default counterStore;

// App.js
import React from 'react';
import { Provider } from 'mobx-react';
import counterStore from './store';
import Counter from './Counter';

function App() {
  return (
    <Provider counterStore={counterStore}>
      <Counter />
    </Provider>
  );
}

export default App;

// Counter.js
import React from 'react';
import { observer, inject } from 'mobx-react';

function Counter({ counterStore }) {
  const { count, increment, decrement } = counterStore;

  return (
    <div>
      <p>{count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
}

export default inject('counterStore')(observer(Counter));

In this example, we define a MobX store in a separate file called store.js. The store is a class that holds the application state and defines methods to update the state. The App component wraps the Counter component with a Provider component from the mobx-react package, which provides the MobX store to all components in the application. The Counter component uses the inject and observer higher-order components from mobx-react to access the store and observe changes in the state.

Zustand

Zustand is a small and lightweight state management library for React applications. It provides a simple API to create and manage state, using hooks and function closures.

Here's an example of using Zustand for state management in React:

// store.js
import create from 'zustand';

const useCounterStore = create(set => ({
  count: 0,
  increment: () => set(state => ({ count: state.count + 1 })),
  decrement: () => set(state => ({ count: state.count - 1 })),
}));

export default useCounterStore;

// App.js
import React from 'react';
import useCounterStore from './store';
import Counter from './Counter';

function App() {
  return (
    <useCounterStore.Provider>
      <Counter />
    </useCounterStore.Provider>
  );
}

export default App;

// Counter.js
import React from 'react';
import useCounterStore from './store';

function Counter() {
  const { count, increment, decrement } = useCounterStore();

  return (
    <div>
      <p>{count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
}

export default Counter;

In this example, we use the create function from the zustand package to create a Zustand store in a separate file called store.js. The store uses the set function to update the state. The App component wraps the Counter component with the Zustand store provider component. The Counter component uses the useCounterStore hook to access the store and its state and actions.

Handling Events in React Components

In React, event handling is similar to traditional HTML event handling. You can attach event handlers to React components using the onEventName prop, where EventName is the name of the event you want to handle, such as onClick, onSubmit, or onChange.

Handling Click Events

To handle click events in React, you can use the onClick prop and assign a function to it.

Here's an example of handling click events in a React component:

import React from 'react';

function Button() {
  const handleClick = () => {
    console.log('Button clicked');
  };

  return <button onClick={handleClick}>Click me</button>;
}

In this example, the handleClick function is called when the button is clicked. It logs a message to the console.

Related Article: The Mechanisms Behind ReactJS’s High-Speed Performance

Handling Form Submission

To handle form submission in React, you can use the onSubmit prop on the form element and assign a function to it.

Here's an example of handling form submission in a React component:

import React, { useState } from 'react';

function Form() {
  const [inputValue, setInputValue] = useState('');

  const handleSubmit = event => {
    event.preventDefault();
    console.log('Form submitted with value:', inputValue);
  };

  const handleChange = event => {
    setInputValue(event.target.value);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" value={inputValue} onChange={handleChange} />
      <button type="submit">Submit</button>
    </form>
  );
}

In this example, the handleSubmit function is called when the form is submitted. It prevents the default form submission behavior and logs the input value to the console. The handleChange function is called when the input value changes and updates the inputValue state.

In React, sharing data between non-related components can be achieved by using a state management library like Redux, MobX, or Zustand. These libraries provide a centralized store that holds the application state and allows components to access and update the state.

Using Redux for Sharing Data

Redux is a popular state management library for React applications. It provides a centralized store that holds the application state and allows components to access and update the state using actions and reducers. With Redux, data can be shared between non-related components by accessing the shared state from the Redux store.

Here's an example of using Redux for sharing data between non-related components:

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

// Reducer function
function dataReducer(state = '', action) {
  switch (action.type) {
    case 'SET_DATA':
      return action.payload;
    default:
      return state;
  }
}

// Create the store
const store = createStore(dataReducer);

export default store;

// ComponentA.js
import React from 'react';
import { useDispatch } from 'react-redux';

function ComponentA() {
  const dispatch = useDispatch();

  const handleClick = () => {
    dispatch({ type: 'SET_DATA', payload: 'Data shared between components' });
  };

  return <button onClick={handleClick}>Set Data</button>;
}

export default ComponentA;

// ComponentB.js
import React from 'react';
import { useSelector } from 'react-redux';

function ComponentB() {
  const data = useSelector(state => state);

  return <p>{data}</p>;
}

export default ComponentB;

In this example, we define a Redux store in a separate file called store.js. The store holds the shared data in the application state. The ComponentA dispatches an action to set the data in the store when the button is clicked. The ComponentB accesses the shared data from the store using the useSelector hook and displays it in a paragraph element. The shared data is now accessible and synchronized between the non-related components.

Additional Resources



- Medium - Sharing Variables Between React Components

- Medium - Using Redux to Share Variables Between React Components

- Medium - Using Mobx to Share Variables Between React Components

You May Also Like

Handling State Persistence in ReactJS After Refresh

This tutorial delves into the intricacies of how state is managed in ReactJS apps and what happens to that state when a component is refreshed. The a… read more

How to Install Webpack in ReactJS: A Step by Step Process

Webpack is a powerful tool used in ReactJS for bundling and managing assets. In this tutorial, we will guide you through the step-by-step process of … read more

Exploring Buffer Usage in ReactJS

Buffering is an important concept in ReactJS for data handling. This article provides a detailed look at how to use Buffer in ReactJS and explores th… read more

How to Send Emails Using ReactJS

Sending emails using ReactJS is a practical tutorial that teaches you how to send emails using ReactJS. From understanding the basics of ReactJS to i… read more

How to Implement Custom CSS in ReactJS

Adding custom CSS in ReactJS can be a process with the right knowledge. This concise article outlines the steps to implement custom CSS in ReactJS, i… read more

Extracting URL Parameters in Your ReactJS Component

URL parameters play a crucial role in web development, especially when working with ReactJS components. In this article, you will learn how to extrac… read more

How to Render a File from a Config in ReactJS

Rendering files from a configuration file in ReactJS can greatly enhance efficiency for advanced users. This article provides a step-by-step guide to… read more

ReactJS: How to Re-Render Post Localstorage Clearing

Re-rendering in ReactJS after clearing the localstorage is a crucial process to understand for developers. This article covers topics such as updatin… read more

Exploring Differences in Rendering Components in ReactJS

In this article, we delve into the intricacies of rendering components in ReactJS, analyzing how ReactDOM.render interacts with different types of co… read more

How to Solve “_ is not defined” Errors in ReactJS

ReactJS is a popular JavaScript library for building user interfaces. However, one common issue that developers encounter is the "_ is not defined" e… read more