DEV Community

Eduardo Gomes
Eduardo Gomes

Posted on • Edited on

Using React Central State to Simplify Your App

React-central-state is an easy-to-use React library created to help you share a common state between your components without passing state to props and minimizing re-rendering. It is available on npm and github.

If you do not want to deal with redux/mobx complexity, or your application is just not that big to justify these tools, I propose a different and simpler approach:


import React from 'react';
import {CSComponent} from 'react-central-state';

class _Component1 extends React.Component {
  ...
  changeFoo(value){
    this.setCentralState({foo:value});
  }
  ...
}

class _Component2 extends React.Component {
  ...
  updateWith(){
    return ['foo','someOtherProperty','anotherOne'];
  }

  render(){
    let foo = this.centralState.foo || "Nothing here";
    return <div>{foo}</div>
  }
}

export const Component1 = CSComponent(_Component1);
export const Component2 = CSComponent(_Component2);


Why Use It

  • Easy to use, requiring almost no additional code.

  • The syntax is very similar to vanilla react state management.

  • It allows all components to read and update from one central state.

  • You can use it along with react’s normal state.

  • Gives you control of what triggers your components to update.

  • Only causes re-rendering when you need it.

When the State Changes…

  • Each component only subscribes to the central state properties changes it is interested in.

  • Components are notified by mounting order.
    shouldComponentUpdate method has nextCentralState injected as third parameter, returning false will avoid a re-render — a.k.a. the default behavior.

How It Works

The store keeps information about the CSComponents mounting order. When a change occurs to its state, updates are dispatched orderly trough components that are observing at least one of the changed properties.

While redux does this by mapping relevant “sub-state” trough each component props, central state asks you to declare all properties that, when changed, require re-rendering.

This orderly dispatching also avoids duplicate render calls caused by either an owner component making children re-render, or changes in state inside callbacks.

The Downside

  • Accessing a central state property in render() that is not returned by updateWith() may lead to “dirty” DOM elements — i.e., not synced with the application state.

  • On the other hand, returning property keys from updateWith() that are not accessed in render() will most likely cause useless re-rendering.
    In the end, you just need to pay attention to what properties render needs to keep up with.

How to use it

You’ll only need to make 2 adjustments to your code:

  • Wrap your exported components with CSComponent

  • Implement updateWith() on wrapped components method and return an array of central state properties that notify the component to update when changing value.

Updating and Reading from the central state:

Pretty much like in vanilla react, use this.setCentralState() to update and read from this.centralState property.
You can also register functions to be called when one or more properties change, right before react components are re-rendered:

import React from 'react';
import {CSComponent} from 'react-central-state';

class Display extends React.Component {
   constructor(props){
     super(props);

     //Register listener for 'foo' object changes
     this.fooListener = this.addCentralStateListener(prevstate=>{
       alert("Foo changing from "+prevstate.foo+" to "+this.centralState.foo);
     },'foo');
   }

   //Dont forget to remove the listener on unmounting
   componentWillUnmount(){
     this.removeCentralStateListener(this.fooListener);
   }

   updateWith(){return ['foo']};

   //Re-render occurs after this.fooListener is called.
   render(){
     return <div>{this.centralState.foo}</div>
   }
}

export default CSComponent(Display);

Next Steps

  • Do some kind of batching on updates when done from the same callback/event handler.

That’s it, if you feel like the pros outweigh the cons I listed here, go ahead and give it a try.

Also, I’ll be glad to know what you think and if you find any problems/bugs please report them on github.

Top comments (7)

Collapse
 
revskill10 profile image
Truong Hoang Dung

The critical difference is: With Redux, i don't need React to describe my application state, React is just the view layer, i could go with vanilla JS or jQuery with Redux.

So this solution is too framework-coupling, so it's not good, or unusable to me.

Collapse
 
juniusfree1 profile image
juniusfree

Hey. Newbie here.

What's the difference of this library from React Context API? TIA

Collapse
 
greenstage profile image
Eduardo Gomes

Hi,
-The Context API lets you create a relationship between one data provider and multiple data consumers.

-Central State kicks the state out of all react components and lets them read and change its properties.

-With Context, either you create a new container for each shared property, or you wrap all properties on the context object. -> But then be ready for a lot useless re-rendering.

-Central State dispatched updates on subscribed properties changing, not the whole state, and also gives you control over them on shouldcomponentupdate().

-With only React Context, if you need to change a state property inside a consumer component, you'll have to define a new function embedded in the context itself.
This may have the advantage of isolating concerns like mutating the state -making it easier to debug- but it also gives you lot of extra work.

Well that's my view on it, at least.
But I like this library mostly because of its simplicity.

Collapse
 
omrisama profile image
Omri Gabay

Thanks, came in here to ask this.

Collapse
 
blnkspace profile image
AVI

that answer demystified it for me! thanks! I'm surely gonna try this out in smaller projects, that don't need redux & redux-saga or Apollo, etc

Collapse
 
zoltanradics profile image
Zholtan Choo

I was using Redux so far amd it always worked, but I find this solution interesting. Sometimes reducers and action creators are too much hassle. I will give this a try at least for a smaller project

Collapse
 
jorge_rockr profile image
Jorge Ramón

Nice, it's an easier approach than redux