React + Redux:组件不会更新

时间:2016-03-15 00:05:59

标签: javascript reactjs redux

尝试使用React + Redux,可能正在做一些明显愚蠢的事情,因为在获取数据时,触发通过网络获取数据的操作的组件不会得到更新(重新呈现)。

以下是我的代码的相关部分:

作为应用的入口点的顶级index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { Router, browserHistory } from 'react-router';
import reduxPromise from 'redux-promise';
import createLogger from 'redux-logger';

const logger = createLogger();

import routes from './routes';
import reducers from './reducers';

const createStoreWithMiddleware = applyMiddleware(reduxPromise, logger)(createStore);

ReactDOM.render(
  <Provider store={createStoreWithMiddleware(reducers)}>
    <Router history={browserHistory} routes={routes} />
  </Provider>
  , document.querySelector('.container'));

顶级容器App:

import React, {Component} from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as Actions from '../actions';
import Header from '../components/header';
import Showcase from '../components/showcase';

function mapStateToProps(state) {
  return {
    resources: state.resources
  }
}

function mapDispatchToProps(dispatch) {
  return {
    fetchResources: () => {
      dispatch(Actions.fetchResources());
    }
  }
}


class App extends Component {

  render() {
    console.log('props in App', this.props);
    return (
      <div>
        <Header/>
        <Showcase
          fetchResources={this.props.fetchResources}
          resources={this.props.resources}
        />
      </div>
    );
  }
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(App)

触发操作以在数据即将挂载时发送数据请求并且应该显示已获取数据的组件:

import React, {Component} from 'react';
import {connect} from 'react-redux';

class Showcase extends Component {
  constructor(props) {
    super(props);
  }

  componentWillMount() {
    this.props.fetchResources();
  }

  render() {
    console.log('resources', this.props);
    return (
      <div>
        This is showcase
      </div>
    );
  }
}

export default connect(state => ({resources: state.resources}))(Showcase)

行动创作者:

import * as types from '../constants/ActionTypes';
import axios from 'axios';

export function fetchResources() {
  return {
    type: types.FETCH_FIRST,
    payload: axios.get('/sampledata/1.json')
  }
}

获取操作的Reducer:

import * as types from '../constants/ActionTypes';

export default function resourcesReducer (state={}, action) {
  switch (action.type) {
    case types.FETCH_FIRST:
      console.log('about to return', Object.assign (state, {resources: action.payload.data }))
      return Object.assign (state, {resources: action.payload.data });
    default:
      return state
  }
};

最后是根减速器:

import { combineReducers } from 'redux';
import navigationReducer from './navigation-reducer';
import resourcesReducer from './resources-reducer';

const rootReducer = combineReducers({
  navigationReducer,
  resourcesReducer
});

export default rootReducer;

所以,这就是我所观察到的。成功触发请求数据的操作,发送请求,reducer在解析promise时接收请求,并使用获取的数据更新状态。此时,我希望顶级App组件和Showcase组件检测到商店已更新并重新渲染,但我没有在控制台中看到它。 / p>

另外,我对redux-logger的控制台输出感到困惑:

enter image description here

具体来说,我很惊讶地看到state包含来自rootReducer的reducer - 我不知道它是否正确(Redux logger Github page上的示例显示没有reducers的状态)。同样令人惊讶的是prev state报告的redux-logger包含与resourcesReducer相同的next state对象,但直觉上我希望prev state更多或state少空了。

请指出我做错了什么以及如何让React组件响应mapStateToProps更改?

=============================================== ===

更新:

1)更改了App组件中的function mapStateToProps(state) { return { resources: state.resourcesReducer } } 函数,使其正确映射到reducer状态:

resources

2)仍然将 render() { console.log('props in App', this.props); return ( <div> <Header navigateActions={this.props.navigateActions}/> React simple starter <Showcase fetchResources={this.props.fetchResources} resources={this.props.resources} /> </div> ); 传递给`Showcase组件:

resources

3)尝试通过对其进行字符串化来显示 render() { console.log('resources', this.props); return ( <div> This is showcase {JSON.stringify(this.props.resources)} </div> ); } ,以查看此对象中的实际内容:

This is showcase {}

在屏幕上看到这一点:next state。该组件似乎不会重新渲染。

以下是控制台的屏幕截图,显示App的道具已使用Object.assign (state, {resources: action.payload.data });中的值进行了更新。但是,这并没有导致组件重新渲染:

enter image description here

再次更新我的javascript-fu也很差劲。我没有意识到通过返回/home/mycamp/public_html/wp 我实际上是在改变状态,并且简单的反转反转会让我实现我的意图。感谢this discussion关于SO的启发。

1 个答案:

答案 0 :(得分:9)

  

令我惊讶的是,状态包含来自rootReducer的缩减器

这是它的工作原理。仔细看看combineReducers()

const rootReducer = combineReducers({
  navigationReducer,
  resourcesReducer
});

认识到它不是参数列表;它是一个单一的对象参数。也许ES5语法更清晰:

var rootReducer = combineReducers({
  navigationReducer: navigationReducer,
  resourcesReducer: resourcesReducer
});

resourcesReducer键指向resourcesReducer()函数返回的状态。也就是说,state中的resourcesReducer()变量只是整个州的一部分。

传递给connect()的函数将整个状态作为参数。你的实际应该是这样的:

export default connect(state => ({
  resources: state.resourcesReducer.resources
}))(Showcase);