Skip to content
Advertisement

How to subscribe on updates within ReactReduxContext.Consumer?

I would like to figure out how to subscribe on updates of a stored value it the redux store.

So far I’ve tried something like the following:

      <ReactReduxContext.Consumer> 
      {({store}) => {
        console.log('store:', store.getState());
        const p = <p>{store.getState().value}</p>;
        store.subscribe(() => {p.innerText = store.getState().value});
        return p;
      }}
      </ReactReduxContext.Consumer>

bumping into the TypeError: can't define property "innerText": Object is not extensible error on updates.

So I wonder how to update the contents?

Advertisement

Answer

There are a few things about your code that are just not the way that we do things in React.

React is its own system for interacting with the DOM, so you should not attempt direct DOM manipulation through .innerText. Your code doesn’t work because the variable p which you create is a React JSX Element rather than a raw HTML paragraph element, so it doesn’t have properties like innerText.

Instead, you just return the correct JSX code based on props and state. The code will get updated any time that props or state change.

The ReactReduxContext is used internally by the react-redux package. Unless you have a good reason to use it in your app, I would not recommend it. There are two built-in ways that you can get a current value of state that is already subscribed to changes.

useSelector hook

(recommended)

export const MyComponent1 = () => {
  const value = useSelector(state => state.value);

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

connect higher-order component

(needed for class components which cannot use hooks)

class ClassComponent extends React.Component {
  render() {
    return <p>{this.props.value}</p>
  }
}

const mapStateToProps = state => ({
  value: state.value
});

const MyComponent2 = connect(mapStateToProps)(ClassComponent)

ReactReduxContext

(not recommended)

If anyone reading this has a good reason why they should need to use store.subscribe(), proper usage would look something like this:

const MyComponent3 = () => {
  const { store } = useContext(ReactReduxContext);
  const [state, setState] = useState(store.getState());

  useEffect(() => {
    let isMounted = true;
    store.subscribe(() => {
      if (isMounted) {
        setState(store.getState());
      }
    });

    // cleanup function to prevent calls to setState on an unmounted component
    return () => {
      isMounted = false;
    };
  }, [store]);

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

CodeSandbox Demo

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement