2016-03-15 153 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

相關問題