Author avatar

Gaurav Singhal

Handle Parent-Child Data Relationships in Redux

Gaurav Singhal

  • Oct 26, 2020
  • 4 Min read
  • 137 Views
  • Oct 26, 2020
  • 4 Min read
  • 137 Views
Web Development
Front End Web Development
Client-side Frameworks
React

Introduction

Redux is an excellent library for state management in client-side JavaScript-based apps. It is framework agnostic, meaning it can be used with any other UI or JavaScript framework. Redux maintains the state of the whole app in a single immutable state object, which cannot be accessed or modified directly.

When working on React-Redux apps, you will come across many use cases where you have to pass and manage data between components. In this guide, you will learn how to handle parent-child data relationships in Redux.

Passing Data Between Components

As mentioned earlier, you cannot change the state object or the global store directly. To change the state object, you need to use actions and reducers. An action is simply a JavaScript object that passes information to reducers, and reducers are pure functions that return an updated state based on the current action that was dispatched.

Consider an example where you have counters in the parent and child components. You need to update the counter in the parent component from the child component and vice-versa.

So the initial, or default, state will look as follows.

1
2
3
4
const initialState = {
    parentCounter: 0,
    childCounter: 0,
};
js

To update the state you need to create a reducer, as shown below.

1
2
3
4
5
6
7
8
9
10
function reducer(state = initialState, action) {
    switch (action.type) {
        case "INCREMENT_PARENT":
            return { ...state, parentCounter: state.parentCounter + 1 };
        case "INCREMENT_CHILD":
            return { ...state, childCounter: state.childCounter + 1 };
        default:
            return state;
    }
}
js

In the parent component, dispatch the INCREMENT_CHILD action so the reducer updates the counter in the child component. To make the dispatch method available as a prop, use the connect() method. Also, pass the mapStateToProps argument to the connect method so the parent's counter value is sent as the prop to the component.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import React, { Component } from "react";
import { connect } from "react-redux";

import Child from "./Child";

class Parent extends Component {
  incrementChildCounter = () => {
    this.props.dispatch({ type: "INCREMENT_CHILD" });
  };
  render() {
    return (
      <div className="parent-component">
        <div>
          This is the parent component - [COUNTER: {this.props.counter}]
        </div>
        <button onClick={this.incrementChildCounter}>
          Increment Child Counter
        </button>
        <Child />
      </div>
    );
  }
}

const mapStateToProps = (state) => ({
  counter: state.parentCounter,
});

export default connect(mapStateToProps)(Parent);
jsx

Follow the same steps for the child component, except the child component needs to dispatch the INCREMENT_PARENT action.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import React, { Component } from "react";
import { connect } from "react-redux";

class Child extends Component {
  incrementParentCounter = () => {
    this.props.dispatch({ type: "INCREMENT_PARENT" });
  };
  render() {
    return (
      <div className="child-component">
        <div>This is the child component - [COUNTER: {this.props.counter}]</div>
        <button onClick={this.incrementParentCounter}>
          Increment Parent Counter
        </button>
      </div>
    );
  }
}

const mapStateToProps = (state) => ({
  counter: state.childCounter,
});

export default connect(mapStateToProps)(Child);
jsx

In the main App component, wrap the Parent component with the Provider component from the react-redux package and pass the store as a prop.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { Provider } from "react-redux";
import { createStore } from "redux";

const store = createStore(reducer);

function App() {
  return (
    <div className="App">
      <Provider store={store}>
        <Parent />
      </Provider>
    </div>
  );
}
jsx

Conclusion

With Redux, you might complain that there is a lot of boilerplate and overhead for creating actions and reducers and architecting the app. Even Redux suggests that you should start with a basic React app and use Redux only when the app state grows and it becomes difficult to predict state. You can refer to this section of the Redux docs to read more on the topic.

1