Universal React/redux未在状态更新时呈现
Universal React/redux not rendering on state update
我使用的是这个样板文件,在我的状态更新后,我的容器没有重新渲染。我有两个操作被调度,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>
);
}
}
根据Redux常见问题解答http://redux.js.org/docs/FAQ.html#react-不重新渲染,99.9%的情况下组件不重新渲染的原因是因为reducer直接改变了状态。这一行似乎正是这样做的:result.data[action.sectionID] = action.data;
。您还需要在result
中返回data
的克隆版本。
现在,我实际上希望"loading"answers"loaded"中的更改将正确地导致组件重新渲染,即使"data"引用保持不变,但这里可能缺少其他内容。
相关文章:
- 更新Redux状态&然后在同一实例中获取更新状态
- 如果我不应该在组件WillUpdate中调用setState,如何更新状态(使用ReactJS)
- 如何在alt.js中使用源成功请求后更新状态
- 实现已验证用户更新状态的最佳方式,作为对系统中已更改状态的反应.(ASP.NET MVC网站)
- 如何使用Redux更新状态
- 使用 OnChange 事件更新状态具有延迟字符
- 在 redux 化简器中更新状态的正确方法
- 在反应本机中更新状态需要很长时间
- React - 如何在 AJAX 请求后更新状态
- onchange 事件更新状态,延迟为 1 个字符
- 在循环中调用 setState 仅更新状态 1 次
- react js和rails在具有活动记录关系的组件上更新状态
- React componentDidMount未更新状态
- 发送整个对象只是为了更新状态
- Javascript的问题.无法更新状态
- 当视图加载时更新状态
- Twitter REST API,更新状态
- 在React Router中,当页面改变时更新状态
- React-redux, connect函数不使用新数据更新状态
- React:将新插入的子元素返回给父元素以更新状态