React-redux: "Changing store on the fly" error when embedding <Provider> in a stateless component

Created on 20 Jan 2016  路  10Comments  路  Source: reduxjs/react-redux

I'm working on a large app where we're slowly integrating Redux piecemeal, essentially converting small components into "embedded Redux apps" that are the top-level of the Redux app, but not the top-level of the React app. This has worked for the most part, but we ran into this issue:

var ReduxRoot = props => (
    <Provider store={props}>
        <ReactReduxConnectedComponent/>
    </Provider>
)

It works fine, but any time the parent component re-renders, a <Provider> does not support changingstoreon the fly error pops up in the console.

This is fixed by adding a shouldComponentUpdate, and returning false if this.props and nextProps are equal. But that prevents us from taking advantage of the stateless component pipeline.

I know it's not the idealized use of Redux to embed it within a React hierarchy instead of at the top level, so I'm not sure if this issue is considered worth addressing. But maybe it is.

Most helpful comment

Throwing in an answer for those who searched for the Error message in the title: Don't call createStore in the provider attribute!

Don't do this:

```js
ReactDOM.render(

,
document.getElementById('root')
);

The correct way is this:

 ```js
var store = createStore(reducers);
ReactDOM.render(
  <Provider store={store}>
    <App/>
  </Provider>,
  document.getElementById('root')
);

All 10 comments

I know it's not the idealized use of Redux to embed it within a React hierarchy instead of at the top level, so I'm not sure if this issue is considered worth addressing. But maybe it is.

It's totally fine, we should support this.

It works fine, but any time the parent component re-renders, a does not support changingstoreon the fly error pops up in the console.

Please see the relevant check. It's comparing identities. This means that the store prop is different on every render. This is problematic. (You're effectively recreating store and destroying its state鈥攚hy?)

This is also a bit weird:

var ReduxRoot = props => (
    <Provider store={props}>
        <ReactReduxConnectedComponent/>
    </Provider>
)

Shouldn't that be more like

var ReduxRoot = props => (
    <Provider store={props.store}>
        <ReactReduxConnectedComponent/>
    </Provider>
)

?

This is also a bit weird:

Aha, that was the problem. Since the initial state of the store was the only data I needed to pass to ReduxRoot, it was basically:

<ReduxRoot {...initialStore}/>

So that meant props, even though it always had the same contents, was actually a new object being passed to <Provider>.

I fixed the problem by using your correction, except with destructuring

var ReduxRoot = ({store}) => {

for an ever-so-satisfying elimination of six characters.

I guess one way to avoid this error is if <Provider> could check to see if the store it's being passed is actually identical to its previous store, but that might add some unnecessary overhead.

Glad you found the problem! Yeah, we only rely on object identity there, something more complicated seems unwarranted.

Sorry for being a bit off topic but I'm looking for a code example that demonstrates switching between different stores in react-native. This thread seems to touch the subject.
Specifically, I want to switch between users (log in/out) where each user has its own store.
Could you point me to any articles/tutorials available online.
Thanks a lot!

Sorry too for being off topic but I'm having the same issue as @beebase. I want to change between stores in a login/logout logic in react-native, and I'm not sure how can that be done. Have you found a solution @beebase ? Thanks!

You can't change the store passed to <Provider>, but you could render a new <Provider>. Give it a key and change it when you change the store.

interesting...

never encountered a case where I need to create 2 stores and switch between them..
can't we put the switch inside store, and read different part from store state? nevertheless, I believe you have your own ground to have 2 stores

Throwing in an answer for those who searched for the Error message in the title: Don't call createStore in the provider attribute!

Don't do this:

```js
ReactDOM.render(

,
document.getElementById('root')
);

The correct way is this:

 ```js
var store = createStore(reducers);
ReactDOM.render(
  <Provider store={store}>
    <App/>
  </Provider>,
  document.getElementById('root')
);

I had the same problem as given in the title but after the advise of @totymedli, i solved my problem. I am using react-native my approach for the solution was as advised;

const store = createStore(reducers);

export default class App extends React.Component {
  render() {
    return (

        <Provider store={store}>
          <View style={{ flex: 1 }}>
            <Header title="Tech Stack" />
            <LibraryList />
          </View>
        </Provider>

    );
  }
}

Here is my solution:

// index.tsx
import createStore from './redux/createStore'
const store = createStore({})

const renderApp = () => {
  ReactDOM.render(
    <MuiThemeProvider theme={theme}>
      <Provider store={store}>
        <Router>
          <App />
        </Router>
      </Provider>
    </MuiThemeProvider>,
    document.getElementById('root'),
  )
}
renderApp()

if (module.hot) {
  // only need replace entry point
  module.hot.accept('./App', () => {
    renderApp()
  })
}

The one important thing is that should not replace the file which create the redux store. In my above example is the index.tsx.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mharrisweb picture mharrisweb  路  3Comments

teosz picture teosz  路  4Comments

nainardev picture nainardev  路  3Comments

esayemm picture esayemm  路  3Comments

owinter86 picture owinter86  路  3Comments