Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

react component connected, redux state changes... but no update to component?

I'm creating a React/Redux front-end for a multi-channel chat app. I'm having problems getting some React components to re-render after state change while using redux, react-redux, and redux-thunk.

I believe that my reducers are non-mutating, and that I'm subscribed via react-redux's connect. When I run the app and view the browser console, I see the initial render of the component (i.e. with initial, empty state), then the state change (triggered by an action dispatch in index.js).... I would then expect the component to re-render with new props, but it doesn't happen.

console log

I've put up a repo here: https://github.com/mattmoss/react-redux-no-update

node_modules is not in the repo, so to run, first download dependencies (running yarn is sufficient), then npm start.

Some excerpts (see full source in repo):

reducers/channelList.js

import * as c from '../actions/constants';

export default function channelList(state = [], action) {
    switch (action.type) {
        case c.FETCH_CHANNELS_SUCCESS:
            return action.channels;
        default:
            return state;
    }
}

actions/channelActions.js

export function fetchChannels() {
    return (dispatch) => {
        return ChannelApi.allChannels()
            .then(channels => dispatch(fetchChannelsSuccess(channels)))
            .catch(error => { throw(error); });
    };
}

export function fetchChannelsSuccess(channels) {
    return {
        type: c.FETCH_CHANNELS_SUCCESS,
        channels
    };
}

components/ChannelListView.js

class ChannelListView extends React.Component {
    render() {
        const { channels, current, onSelect } = this.props;

        console.log("channels:", channels, "current:", current);

        return (
            <ListGroup>
                {channels.map(channel =>
                    <ListGroupItem
                        key={channel.id}
                        active={channel.id === this.props.current}
                        onClick={onSelect(channel.id)}
                    >
                        <strong>#{channel.name}</strong>
                    </ListGroupItem>
                )}
            </ListGroup>
        );
    }
}

export default ChannelListView;

containers/ChannelList.js

import ChannelListView from '../components/ChannelListView';

const mapStateToProps = (state, ownProps) => {
    return {
        channels: state.channelList,
        current: state.currentChannel
    };
};

const mapDispatchToProps = (dispatch) => {
    return {
        onSelect: (id) => () => {}
    };
};

export default connect(mapStateToProps, mapDispatchToProps)(ChannelListView);

App.js

class App extends Component {
  render() {
    return (
      <Grid>
        <Row>
          <Col>
            <h1>Channels</h1>
            <ChannelList />
          </Col>
        </Row>
      </Grid>
    );
  }
}

index.js

const store = configureStore();
store.dispatch(fetchChannels());

ReactDOM.render(
    <Provider store={configureStore()}>
        <App />
    </Provider>,
    document.getElementById('root')
);

store/configureStore.js

import { createStore, applyMiddleware } from 'redux';
import rootReducer from '../reducers/rootReducer';
import thunk from 'redux-thunk';
import logger from 'redux-logger';

export default function configureStore() {
    return createStore(
        rootReducer,
        applyMiddleware(thunk, logger)
    );
}
like image 944
Matthew Moss Avatar asked May 09 '17 22:05

Matthew Moss


People also ask

Why is React not updating on state change?

State updates in React are asynchronous; when an update is requested, there is no guarantee that the updates will be made immediately. The updater functions enqueue changes to the component state, but React may delay the changes, updating several components in a single pass.

Does component Rerender When Redux state change?

Your component is only going to re-render if its state or props are changed.

What happens when Redux state changes?

The fact that the Redux state changes predictably opens up a lot of debugging possibilities. For example, using time travel makes it possible to travel back and forth between different states instead of having to reload the whole app in order to get back to the same place.

How do I refresh Redux state?

You need to create a selector and use it in your component to re-render your component after the state changes. Updating the state with proper action (to update username) will cause a re-render in the Topbar component to get the new username from the store.


1 Answers

I'm not 100% as I am still relatively new to React myself. But look at your index.js script.

// You configure the store, then dispatch the fetchChannels action
const store = configureStore();
store.dispatch(fetchChannels());

ReactDOM.render(
    // But here, you're recreating the store again, which I think will re-initialise an empty store
    // Change this to use the `store` variable from above.
    <Provider store={configureStore()}>
        <App />
    </Provider>,
    document.getElementById('root')
);
like image 164
fubar Avatar answered Sep 27 '22 19:09

fubar