React + Redux:组件不更新

aza*_*gru 12 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'));
Run Code Online (Sandbox Code Playgroud)

顶级容器应用:

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)
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)

动作创作者:

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

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

用于获取操作的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
  }
};
Run Code Online (Sandbox Code Playgroud)

最后是根减速器:

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

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

export default rootReducer;
Run Code Online (Sandbox Code Playgroud)

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

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

在此输入图像描述

具体来说,我很惊讶地看到state来自rootReducer 的包含reducers - 我不知道它是否正确(Redux logger Github页面上的示例显示没有reducers的状态).似乎令人惊讶的是prev state,报告的redux-logger内容包含与之相同的resourcesReducer对象next state,尽管直觉上我希望prev state或多或少是空的.

你能否指出我做错了什么以及如何让React组件响应state变化?

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

更新:

1)更改了组件中的mapStateToProps函数,App以便它正确映射到reducer状态:

function mapStateToProps(state) {
  return {
    resources: state.resourcesReducer
  }
}
Run Code Online (Sandbox Code Playgroud)

2)仍然resources向下传递给`Showcase组件:

  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>
    );
Run Code Online (Sandbox Code Playgroud)

3)尝试resources通过对其进行字符串化来显示在屏幕上以查看此对象中的实际内容:

  render() {
    console.log('resources', this.props);
    return (
      <div>
        This is showcase {JSON.stringify(this.props.resources)}
      </div>
    );
  }
Run Code Online (Sandbox Code Playgroud)

在屏幕上看到这个:This is showcase {}.该组件似乎没有重新渲染.

这是控制台的屏幕截图,显示App的道具已更新了来自的值next state.但是,这不会导致组件重新呈现:

在此输入图像描述

再次更新:我的javascript-fu也很差.我没有意识到通过返回Object.assign (state, {resources: action.payload.data });我实际上是在改变状态,而简单的反转反转会让我实现我的意图.感谢关于SO的启发讨论.

Dav*_*lsh 9

令我惊讶的是,状态包含来自rootReducer的reducer

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

const rootReducer = combineReducers({
  navigationReducer,
  resourcesReducer
});
Run Code Online (Sandbox Code Playgroud)

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

var rootReducer = combineReducers({
  navigationReducer: navigationReducer,
  resourcesReducer: resourcesReducer
});
Run Code Online (Sandbox Code Playgroud)

resourcesReducer对国家重点用返回的resourcesReducer()功能.也就是说,其中的state变量resourcesReducer()只是整个状态的一部分.

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

export default connect(state => ({
  resources: state.resourcesReducer.resources
}))(Showcase);
Run Code Online (Sandbox Code Playgroud)

  • 好的,现在我明白发生了什么.我的`Object.assign`也错了.我正在改变状态:`return Object.assign(state,{resources:action.payload.data})`而我真正需要做的是返回一个新对象(例如`return Object.assign({resources:action} .payload.data},state)`).傻我.虽然似乎是一个常见的错误; 我错过了一个非常类似的帖子:http://stackoverflow.com/questions/33140008/react-redux-store-updates-but-react-does-not (2认同)