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>; };