Universal React/redux未在状态更新时呈现

Universal React/redux not rendering on state update

本文关键字:更新 状态 React redux Universal      更新时间:2023-09-26

我使用的是这个样板文件,在我的状态更新后,我的容器没有重新渲染。我有两个操作被调度,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"引用保持不变,但这里可能缺少其他内容。