Sharing Variables Between Components in ReactJS

Avatar

By squashlabs, Last Updated: December 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: Exploring Differences in Rendering Components in ReactJS

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: How Component Interaction Works 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.

Related Article: How to Style Components in ReactJS

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.

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.

Related Article: How To Pass Parameters to Components in ReactJS & TypeScript

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.

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.

Related Article: Extracting URL Parameters in Your ReactJS Component

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: Implementing onclick Events in Child Components with ReactJS

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.

Related Article: How to Add Navbar Components for Different Pages in ReactJS

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.

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.

Related Article: How To Add Custom HTML in ReactJS Components

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

How to Build Forms in React

Learn how to create forms in React using simple steps. This article provides an introduction to building forms and an overview of form components. It also covers... read more

Handling Routing in React Apps with React Router

Handling routing in React apps using React Router is a crucial skill for any React developer. This article provides a comprehensive guide to understanding and... read more

How to Manage Query Parameters Across Components in ReactJS

Handling query across components in ReactJS can be a complex task. This article will guide you through the process of managing query across different ReactJS components.... read more

Implementing Server Rendering with Ruby on Rails & ReactJS

This article offers a comprehensive examination of server rendering in ReactJS on Rails. The article explores the importance, benefits, and limitations of server... read more

Crafting a Function within Render in ReactJS

This tutorial is a concise walkthrough that guides you on how to write a function within the render method of ReactJS. This article covers various topics such as ReactJS... 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 updating state, React... read more