2016-03-15 150 views
8

尝试使用React + 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')); 

顶层容器应用程序:

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') 
    } 
} 

减速的获取操作:

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在解决承诺时收到请求,并使用获取的数据更新状态。此时,我期望顶级App组件和Showcase组件检测到商店已更新并重新渲染,但我在控制台中看不到它。

而且,我被redux-logger的控制台输出困惑:

enter image description here

具体来说,我奇怪为什么地看到,state包含来自rootReducer减速 - 我不知道这是否是正确的( Redux logger Github page上的示例显示了没有缩减器的状态)。令人惊讶的是,由redux-logger报告的prev state包含与next state相同的resourcesReducer对象,尽管直观地我期望prev state或多或少是空的。

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

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

更新:

1)在App部件改变了mapStateToProps功能,使得它正确地映射到减速机状态:

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

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> 
    ); 

3)试图通过字符串化它,看看有什么实际上是这个对象内部,以显示在屏幕上resources

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

看到这个屏幕上:This is showcase {}。该组件似乎不会重新渲染。

下面是控制台的屏幕截图,显示App的道具已经更新了next state的值。不过,这并没有导致组件重新渲染:

enter image description here

再次更新:而我的JavaScript富穷了。我并不完全意识到,通过返回Object.assign (state, {resources: action.payload.data });我实际上是在颠覆国家,而且一个简单的论证倒置可以让我达到我的目的。感谢this discussion对SO的启发。

+0

你是否尝试向root reducer对象添加密钥? 'const rootReducer = combineReducers({navigation:navigationReducer, resources:resourcesReducer });' – anoop

回答

6

我奇怪为什么看到的状态包含减速从rootReducer

这是如何工作的。仔细看看combineReducers()

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

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

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

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

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

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

谢谢。你的评论更清楚地表明了状态和reducer(和combineReducers)之间的关系,但是即使在我更新我的代码之后(请参阅我的原始问题的UPDATED部分),状态的更新也不会导致组件的重新渲染。我现在只向应用商店订阅我的'App'组件,并且改变了'mapStateToProps'函数返回'{resources:state.resourcesReducer}'。我看到状态更新,并且'App'的道具反映了这种变化,但这不会导致App(或Showcase)重新渲染。我错过了什么? – azangru

+1

好吧,现在我明白发生了什么事。我的'Object.assign'也是错误的。我正在改变状态:'返回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 – azangru

相关问题