ic3
ic3

Reputation: 7690

React/Redux : Events - state of the art

What is the state of the art in React to implement an event based pattern ( Publisher / Subscriber).

From one side we have components that listen to those events. Some of these components are visual, e.g. a chart that draws the result of a query other might not be visual, e.g. if we want to have components that manage queries and results.

From the other, any component can generate events.

Our first idea is adding in Redux the full list of events and their values and on each component implement in shouldComponentUpdate() a smart code that stops if the component does not listen to the changed events.

This doesn't look very elegant as all components listen to all events. Is there a more elegant solution (kind of state of the art) ?

Of course we want to be able to go back, forwars, save state and all this small details :-)

Upvotes: 4

Views: 1035

Answers (2)

Ed I
Ed I

Reputation: 7368

I think what you need to know is not so much "What is the state of the art" as "What is the canonical way" of doing publish and subscribe with React and Redux.

The short answer is that if you have a complex enough application, you should organize your store so that the application state is divided into slices and use the container pattern to separate the responsibility of publishing and subscribing. This way you avoid the problem you mentioned where you don't know what in the code base is changing the store and what is responding to the changes. You can look at a container component and see how it handles UI events from its children and produces a state change event. Or you can see how the container handles a state change and then drill-down the hierarchy. If you can make a Redux slice the responsibility of a single container, it's that much easier to think about events. All other components are not subscribed to the events per se, instead they receive the changes they need to render from props originating from the container component. And they notify the container component of their own events through callbacks passed down through props, so the container can publish them. This can go a long, long way, and if you feel that you need to pass down props too many levels, you can use React.children to flatten the nesting a bit, or in rare cases context.

The longer answer is a bit more difficult, since publish and subscribe is not super meaningful when talking about React. React should ultimately be responsible for rendering. As you mentioned, not all events are UI events. But if you model things such that all events that you can publish and subscribe to boil down to changing the store or reacting to a store change, then you can build your app focused more on Redux. Managing the queries and results you're talking about should be done in simple JavaScript modules without React. Then you can use a container component to glue the store to that module.

There are additional patterns people use like action creators and selectors. Those are good because at least the intent is to keep code bases familiar. But things are still moving a bit fast, with React moving towards the Hooks API and React-Redux trying to catch-up. But slices and container components aren't going anywhere, they are a natural way to separate concerns.

Upvotes: 2

Radu Luncasu
Radu Luncasu

Reputation: 1073

redux to store the events reselect/connect to subscribe to them (https://github.com/reduxjs/reselect#connecting-a-selector-to-the-redux-store)

import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
import TodoList from '../components/TodoList'
import { getVisibleTodos } from '../selectors'

const mapStateToProps = (state) => {
  return {
    todos: getVisibleTodos(state)
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id))
    }
  }
}

const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

export default VisibleTodoList

Now you have your subscribed event as a prop in the component, the component will re-render only if the prop changes. No need for shouldComponentUpdate because your component doesn't have to listen to the whole store, it will only get the part of the store you define in the selector.

Upvotes: 1

Related Questions