React组件不从Redux Store渲染新数据

时间:2017-04-01 23:12:35

标签: reactjs socket.io redux react-redux immutable.js

这个问题发挥作用,因为我在通过redux存储形式的websocket获取初始状态之前调用了高级组件。因此,当我的组件处理状态时,它们只接收默认状态,即空的不可变映射()。但是,在某些时候我从服务器接收商店,我从我的action_creators调用setState,并由我的reducer处理,它将商店合并到我的本地商店。使用redux-logger记录整个过程。请参阅相关的屏幕截图您可以看到本地状态已更改但组件未重新呈现。

Redux-logger output < - 组件状态是高级组件接收的内容。

我知道我的动作和减速器在某种程度上起作用,因为如果我将本地JSON文件与本地存储器合并,则组件接收的状态不仅仅是一个空的Map,而是包含完整的状态数据。但是,这并不意味着重新渲染工作,我假设状态只是进程,因为它在最初调用组件之前可用。

请查看我的index.js,action_creators.js,reducer.js和我的高级组件Game

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import {createStore, applyMiddleware} from 'redux';
import {Provider} from 'react-redux';
import {setState} from './action_creators';
import io from 'socket.io-client';
import logger from 'redux-logger';

import routes from './routes.js';
import reducer from './reducer';
import InitialState from './initial.json';
import './index.scss';

const socket = io(`${location.protocol}//${location.hostname}:8090`);
const store = createStore(
  reducer,
  applyMiddleware(logger)
);

socket.on('state', state => store.dispatch(setState(state)));
// socket.on('state', state => console.log("From Store", store.getState()));
// socket.on('state',store.dispatch(setState(InitialState)));
// console.log("From JSON",InitialState);

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

reducer.js

import {Map} from 'immutable';

export default function(state = Map(), action) {
  switch (action.type) {
    case 'SET_STATE':
      return state.merge(state, action.state);
    default:
      return state;
  }
}

action_creators.js

export function setState(state) {
  return {type: 'SET_STATE',state};
}

export function modIndicator(state, playerId, indicator, modifier) {
  return {type: 'INDICATORS', playerId: playerId, indicator: indicator, modifier: modifier};
}
export function modCollection(state, collection, property, value, op, category) {
  return {
    type:'COLLECTIONS',
    collection:collection,
    property:property,
    value:value,
    op:op,
    category:category};
}

Game.js

import React, {PureComponent, PropTypes} from 'react';
// import Card from '../../Components/Card/index.js';
// import Collection from '../../Components/Collection/index.js';
import Indicator from '../../Components/Indicator/index.js';
import Counter from '../../Components/Counter/index.js';
import {connect} from 'react-redux';
import * as actionCreators from './../../action_creators.js';
import './styles.scss';

export default class Game extends PureComponent {
  render() {
let playersById = this.props.playersById;
let collections = this.props.collections;
let counters = this.props.counters;

let indic_list = [];
let coll_list = [];

//Indicators
playersById.forEach(function(value, key, map){
  indic_list.push(<p className="section-name">{playersById.get(key).get('name')+"'s Indicators"}</p>)
  playersById.get(key).get('indicators').forEach(function(value, key, map){
      indic_list.push(<Indicator label={key}>{value}</Indicator>)
  });
});

//Collections
collections.forEach(function(value, key, map) {
  coll_list.push(<span>{key}: {collections.get(key).get("content").size}</span>);
  collections.get(key).get("control").forEach(function(value, key, map){
      coll_list.push(<span>Control: {value}</span>);
  });
});

return (
    <div className="frame">
      <div className="left-col">
        {indic_list}
      </div>
      <div className="center-col">
        <span className="collections">
          {coll_list}
        </span>
      </div>
      <div className="right-col">
        <div className="counters">
          {counters.map(function(type){
            return <Counter label={type}></Counter>
          })}
        </div>
      </div>
    </div>
  )
  }
}

Game.PropTypes = {
  playersById:  PropTypes.object.isRequired,
  collections: PropTypes.object.isRequired,
  counters: PropTypes.object.isRequired
}
function mapStateToProps(state) {
  console.log("Component State",state);
  return {
    playersById: state.get('playersById'),
    collections: state.get('collections'),
    counters: state.get('counters')
  };
}
export const GameContainer = connect(mapStateToProps, actionCreators)(Game);

1 个答案:

答案 0 :(得分:1)

您前面有3个选项:

1。设置组件可以使用的初始状态

import {fromJS} from 'immutable';

const initialState = fromJS({
    playersById: [],
    collections: [],
    counters: []
});

export default function(state = initialState, action) {
  switch (action.type) {
    case 'SET_STATE':
      return state.merge(state, action.state);
    default:
      return state;
  }
}

2。如果缺少数据,请提供一些合适的数据

import {List} from 'immutable';

function mapStateToProps(state) {
  console.log("Component State",state);
  return {
    playersById: state.get('playersById') || new List(),
    collections: state.get('collections') || new List(),
    counters: state.get('counters') || new List()
  };
}

这可能更安全,因为您的状态每次都被完全替换,因此如果传入的数据不适合渲染,这将保护您的组件

3。使组件处理缺少的数据

render() {

if (!(playersById && collections && counters)) {
    return null; // or a loading spinner?
}

// ... the rest of your render function

}