我使用this boilerplate并遇到问题,我的容器在状态更新后没有重新渲染。我有两个被调度的动作,1)LOAD - 在AJAX请求开始时调度和2)LOAD_SUCCESS - 一旦数据成功返回。
从reducer调用LOAD_SUCCESS操作,但之后没有任何反应。这个代码曾经在几周前工作(项目暂停了一段时间),但不再有效。有什么想法吗?
import superagent from 'superagent';
import config from '../../config';
const LOAD = 'cnnm/sectionFront/LOAD';
const LOAD_SUCCESS = 'cnnm/sectionFront/LOAD_SUCCESS';
const LOAD_FAIL = 'cnnm/sectionFront/LOAD_FAIL';
const initialState = {
loaded: false,
loading: false,
currentSection: null,
data: {}
};
export default function reducer(state = initialState, action = {}) {
switch (action.type) {
case LOAD:
return {
...state,
loading: true,
loaded: false
};
case LOAD_SUCCESS:
const result = {
...state,
loading: false,
loaded: true,
error: null,
currentSection: action.sectionID
};
result.data[action.sectionID] = action.data;
return result;
case LOAD_FAIL:
return {
...state,
loading: false,
loaded: true,
data: null,
error: action.error
};
default:
return state;
}
}
export function load() {
return (dispatch, getState) =>{
dispatch({
type: LOAD
});
const globalState = getState();
const endpoint = config.endpoints.sectionFronts[globalState.routing.locationBeforeTransitions.pathname];
if ( globalState.sectionFront.data[globalState.routing.locationBeforeTransitions.pathname] === undefined ){
superagent.get( endpoint )
.end( (err, resp) => {
if ( err ){
dispatch({
type: LOAD_FAIL,
error: err
});
}
else {
try {
const data = JSON.parse( resp.text );
dispatch({
type: LOAD_SUCCESS,
sectionID: globalState.routing.locationBeforeTransitions.pathname,
data
});
}
catch ( error ){
console.warn('Error trying to parse section front', error);
dispatch({
type: LOAD_FAIL,
error: error
});
}
}
});
}
else {
// Already have the data cached
dispatch({
type: LOAD_SUCCESS,
sectionID: globalState.routing.locationBeforeTransitions.pathname,
data: globalState.sectionFront.data[globalState.routing.locationBeforeTransitions.pathname]
});
}
};
}
货柜代码:
import React, {Component, PropTypes} from 'react';
import {connect} from 'react-redux';
import Helmet from 'react-helmet';
import Col from 'react-bootstrap/lib/Col';
import Row from 'react-bootstrap/lib/Row';
import { asyncConnect } from 'redux-async-connect';
import { load as loadSectionFront } from 'redux/modules/sectionFront';
import {bindActionCreators} from 'redux';
import { Loading } from 'components';
import Grid from 'react-bootstrap/lib/Grid';
import { cards as cardComponents } from 'components';
@asyncConnect([{
deferred: true,
promise: ({store: {dispatch, getState}}) => {
return dispatch(loadSectionFront());
}
}])
@connect(
state => {
return {
section: state.sectionFront.data,
currentSection: state.sectionFront.currentSection,
loaded: state.sectionFront.loaded,
loading: state.sectionFront.loading
};
},
dispatch => bindActionCreators( {loadSectionFront}, dispatch)
)
export default class SectionFront extends Component {
static propTypes = {
section: PropTypes.object,
loaded: PropTypes.bool,
loading: PropTypes.bool,
currentSection: PropTypes.string,
loadSectionFront: PropTypes.func,
}
mapSecionNameToPrettyName = ( sectionID ) => {
switch ( sectionID ){
case '/':
return 'Top News';
case '/video':
return 'Video';
case '/technology':
return 'Technology';
case '/media':
return 'Media';
case '/investing':
return 'Investing';
case '/news/economy':
return 'Economy';
case '/pf':
return 'Personal Finance';
case '/retirement':
return 'Retirement';
case '/autos':
return 'Autos';
case '/smallbusiness':
return 'Small Business';
case '/news/companies':
return 'Companies';
case '/luxury':
return 'Luxury';
case '/real_estate':
return 'Real Estate';
default:
return 'Not found';
}
}
render() {
const {section, loaded, currentSection, loading } = this.props;
const sectionName = this.mapSecionNameToPrettyName( currentSection );
const styles = require('./SectionFront.scss');
let cardNodes = '';
if (loaded){
cardNodes = section[currentSection].cards.map((card, index) => {
switch ( card.cardType ) {
case 'summary':
if ( card.images === undefined || card.cardStyle === 'text'){
return <cardComponents.SummaryTextComponent card={card} key={index} />;
}
else {
if ( card.cardStyle === 'default' ){
return <cardComponents.SummaryDefault card={card} key={index} />;
}
else if ( card.cardStyle === 'jumbo' || card.cardStyle === 'jumboBlack' ){
return <cardComponents.SummaryJumboComponent card={card} key={index} />;
}
else if ( card.cardStyle === 'jumboOverlay' ){
return <cardComponents.SummaryJumboOverlayComponent card={card} key={index} />;
}
}
break;
case 'marketIndices':
return <cardComponents.MarketIndicesComponent key={index} />;
case 'ad':
return <cardComponents.AdComponent card={card} key={index} />;
case 'bizDev':
return <cardComponents.BizDevComponent card={card} key={index} />;
default:
return ( <div key={index}> </div>);
}
});
}
return (
<div className={styles.sectionFront}>
{ loading ? <div className={styles.overlay}><Loading /></div> : null }
<Grid className={styles.container}>
<Row className={styles.sectionTitle}>
<Col className={ 'col-xs-12 ' + styles.sectionCol}>
<h1 className="container">{sectionName}</h1>
</Col>
</Row>
{cardNodes}
</Grid>
</div>
);
}
}
答案 0 :(得分:0)
根据http://redux.js.org/docs/FAQ.html#react-not-rerendering的Redux常见问题解答,99.9%的时间组件未重新渲染的原因是由于reducer直接改变了状态。这一行似乎就是这样做的:result.data[action.sectionID] = action.data;
。您还需要在data
内返回result
的克隆版本。
现在,我实际上会期望“加载”和“加载”中的更改会正确地导致组件重新渲染,即使“数据”引用保持不变,但可能还有其他我遗漏的东西这里。