React + Redux:组件不更新
尝试使用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
的控制台输出困惑:
具体来说,我奇怪为什么地看到,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
的值。不过,这并没有导致组件重新渲染:
再次更新:而我的JavaScript富穷了。我并不完全意识到,通过返回Object.assign (state, {resources: action.payload.data });
我实际上是在颠覆国家,而且一个简单的论证倒置可以让我达到我的目的。感谢this discussion对SO的启发。
我奇怪为什么看到的状态包含减速从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);
谢谢。你的评论更清楚地表明了状态和reducer(和combineReducers)之间的关系,但是即使在我更新我的代码之后(请参阅我的原始问题的UPDATED部分),状态的更新也不会导致组件的重新渲染。我现在只向应用商店订阅我的'App'组件,并且改变了'mapStateToProps'函数返回'{resources:state.resourcesReducer}'。我看到状态更新,并且'App'的道具反映了这种变化,但这不会导致App(或Showcase)重新渲染。我错过了什么? – azangru
好吧,现在我明白发生了什么事。我的'Object.assign'也是错误的。我正在改变状态:'返回Object.assign(state,{resources:action.payload.data})',而我真正需要做的是返回一个新的对象(例如'return Object.assign({resources:action .payload.data},state)')。傻我。似乎是一个常见的错误,虽然;有一个非常类似的帖子,我错过了:http://*.com/questions/33140008/react-redux-store-updates-but-react-does-not – azangru
你是否尝试向root reducer对象添加密钥? 'const rootReducer = combineReducers({navigation:navigationReducer, resources:resourcesReducer });' – anoop