Chris Chris - 2 months ago 15
React JSX Question

Why is react-redux creating multiple states?

Not a problem as such, just a question.

I'm using React-Redux to handle my application state. I've connected my highest level component, named

Academy
, with
mapStateToProps
,
mapDispatchToProps
etc.

I then have a child component,
SlideOverBar
which is connected only for dispatches with the following line of code:

export default connect(null, mapDispatchToProps)(SlideOverBar);


Now, everything works as expected, but for some reason in my React Developer Tools, the
SlideOverBar
component has a full copy of the state. This state is never updated, but I'm concerned in case it may cause any issues down the line. Can anyone tell me - is this normal and if not, what can I do about it.

To clarify, here's some screenshots from the Developer tools:

The Academy component, where the state updates when required. You can see that the
workshopSelection.selectedLevel
piece of state has been updated from
null
to
4
, which is as it should be:

Academy Component

The
SlideOverBar
component. The state here is a copy of the state in
Academy
. It never updates (which is good - the
Academy
state should be controlling the application) but I don't understand why it is there in the first place. The
mapStateToProps
value on this component is set to
null
.

SlideOverBar Component

UPDATE

Here's the full code for each of the components.

Academy:

import React, {Component, PropTypes} from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import {showSlideOver, hideSlideOver} from '../../data/actions/actions';
import styles from '../../cssPartials/Academy.css';
import TopBar from './../TopBar';
import SideMenu from './../SideMenu';
import ViewPort from './../ViewPort';
import SlideOverBar from '../slideOver/SlideOverBar';

class Academy extends Component {

render(){

return (
<div className={styles.academy}>
<div className={styles.spacer} />
<TopBar />
<div className={styles.container}>
<SideMenu />
<ViewPort>
{this.props.children}
</ViewPort>
</div>
<SlideOverBar slideOver={this.props.slideOver}
workshopSelection={this.props.workshopSelection}
slideOverAction={this.props.hideSlideOver}
/>
</div>
)
}

}

function mapStateToProps(state){
return {
slideOver: state.slideOver,
workshopSelection: state.workshopSelection
}
}

function mapDispatchToProps(dispatch){
return bindActionCreators({ showSlideOver: showSlideOver, hideSlideOver: hideSlideOver }, dispatch);
}

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


SlideOverBar:

import React, {Component} from "react";
import styles from '../../cssPartials/slideOverBar.css';
import SlideOverBarTop from './SlideOverBarTop';
import NewWorkshop from './NewWorkshop';
import EditWorkshop from './EditWorkshop';
import UploadSlides from './UploadSlides';
import UploadWorkbook from './UploadWorkbook';
import ViewWorkbook from './ViewWorkbook';
import UploadResources from './UploadResources';
import ViewResources from './ViewResources';
import constants from '../../data/constants.js';
import {chooseLevel, chooseVenue, chooseUnit, showCourses, dayCounter, chooseTutor, resetWorkshops } from '../../data/actions/actions';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';

class SlideOverBar extends Component {

loadContent(testCase){
switch (testCase){
case constants.ADD_WORKSHOP:
return <NewWorkshop properties = {this.props} />
case constants.EDIT_WORKSHOP:
return <EditWorkshop properties = {this.props} />
case constants.UPLOAD_SLIDES:
return <UploadSlides properties = {this.props} />
case constants.UPLOAD_WORKBOOK:
return <UploadWorkbook properties = {this.props} />
case constants.VIEW_WORKBOOK:
return <ViewWorkbook properties = {this.props} />
case constants.UPLOAD_RESOURCES:
return <UploadResources properties = {this.props} />
case constants.VIEW_RESOURCES:
return <ViewResources properties = {this.props} />
default:
return <div>Uh oh, something went wrong!</div>
}

}

render(){
return (
<div className={this.props.slideOver.visible ? `${styles.slideOverBar} ${styles.visible}`
: styles.slideOverBar }>
<SlideOverBarTop slideOverAction = {this.props.slideOverAction}
reset = {this.props.resetWorkshops}
title = {this.props.slideOver.content} />
{this.loadContent(this.props.slideOver.content)}
</div>
)
}
}

function mapDispatchToProps(dispatch){
return bindActionCreators({ chooseLevel, chooseVenue, chooseUnit, showCourses, chooseTutor, resetWorkshops }, dispatch);
}


export default connect(null, mapDispatchToProps)(SlideOverBar);


Any ideas?

Answer

This is nothing to worry about. You are just seeing the HOC Connect that is used by the connect function. This component uses the whole store context underneath. This is just a reference to the store and is not copying.

If you checkout out this line of code from connect, you can see that the Connect component is pulling the full store and setting it as its state.

const storeState = this.store.getState()
this.state = { storeState }

This allows the Connect component to then bind particular store values in with mapStateToProps. But since you are passing null it will default to:

const defaultMapStateToProps = state => ({})