Huy
Huy

Reputation: 11206

Updating my store does not re-render my component

I have a top-level component where I create the store and pass it to its child component, SubscriptionForm:

App.js

import React, { Component } from 'react';
import Navbar from './components/Navbar.js';
import SubscriptionForm from './components/SubscriptionForm.js';
import { createStore } from 'redux'
import rootReducer from './reducers'

const store = createStore(rootReducer)

class App extends Component {
  render() {
    return (
      // Navbar
      <div>
        <Navbar/>
        <SubscriptionForm store={store} />
      </div>
    );
  }
}

export default App;

In my SubscriptionForm component, I render a form where if a user submits it, I dispatch an action to update the store. This is where I'm stuck - render does not get called again.

import React from 'react';

class SubscriptionForm extends React.Component {
  constructor(){
    super();
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleSubmit(e) {
    e.preventDefault();
    this.props.store.dispatch({type: 'SET_SUBSCRIBED'})
    //TODO: persist data to db
  }

  render() {
    if(this.props.store.getState().subscription){
      return (
        <p>Hi</p>
      )
    }else{
      return (
        <form onSubmit={this.handleSubmit} className='subscription-form'>
          <input type='text' placeholder='email' />
          <input type="submit" name="commit" />
        </form>
      )
    }
  }
}

export default SubscriptionForm;

reducers/index.js

import { combineReducers } from 'redux'

const initialSubscription = {
  subscribed: false
}

const subscription = (state = initialSubscription, action) => {
  switch (action.type) {
    case 'SET_SUBSCRIBED':
      return true
    default:
      return state.subscribed
  }
}

const rootReducer = combineReducers({
  subscription
})

export default rootReducer

Does the component not rerender when a state or prop of the component changes? (Where am I goofing up here?)

Upvotes: 0

Views: 333

Answers (2)

Chris C.
Chris C.

Reputation: 139

Dispatching a store action changes the store object but does not trigger a component render refresh by default because you haven't subscribed to the store.

Assuming that you're manually accessing the store while most likely learning react, you'll need to employ a trick to re-render the component whenever you dispatch an action.

In your ReactDom render function, subscribe that render function to the store. Now, each time the store dispatches an action, the subscribed render function will be called.

index.js

const render = () =>
  ReactDOM.render(
    <App store={store}/>,
    document.getElementById('react-container')
  );
store.subscribe(render);
render();

As mentioned above, once you move beyond learning stage, you'll use the react-redux connect HOC function. It'll handle subscribing to the store for you.

Upvotes: 1

markerikson
markerikson

Reputation: 67439

It looks like you're trying to access the store manually. Don't do that! The React-Redux package provides the connect function, which generates wrapper components that handle the store subscription and update process for you.

Upvotes: 1

Related Questions