componentWillReceiveProps不会触发

时间:2018-01-30 15:54:38

标签: javascript reactjs

我有以下高阶组件在我的组件上创建加载:

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import Spinner from 'components/spinner';

const WithSpinner = (WrappedComponent) => {
  return class SpinnerWrapper extends Component {
    componentWillReceiveProps(nextProps) {
      console.log('Current props: ', this.props);
      console.log('Next props: ', nextProps);
    }

    render (){
      const { loading } = this.props;
      return (
        <div>
        {loading ?
          <Spinner />
          :
          <WrappedComponent {...this.props}>{this.props.children}</WrappedComponent>}
        </div>)
    }
  }

  SpinnerWrapper.propTypes = {
    loading: PropTypes.bool,
  };

  SpinnerWrapper.defaultProps = {
    loading: true,
  };

  return SpinnerWrapper;
};

export default WithSpinner;

我有以下组件包装在WithSpinner中

const updateChartSeries = answersSummary => ({
  chartSeries: TasksTransforms.fromAnswerSummaryToClickEffectivenessChart(answersSummary),
  transposed: false,
  viewOptions: { type: 'pie', stacked: false, column: false },
});

class ClickEffectivenessChart extends Component {
  constructor(props) {
    super(props);
    this.state = {
      chartSeries: [],
      viewOptions: {
        type: 'pie',
        stacked: false,
        column: false,
      },
      title: 'Click Effectiveness',
    };
  }

  componentWillReceiveProps({ answersSummary }) {
    this.setState(updateChartSeries(answersSummary));
  }

  handleChartType = (type = 'pie') => {
    switch (type) {
      case 'pie':
        this.setState({ viewOptions: { type: 'pie', stacked: false, column: false } });
        break;
      case 'bar':
        this.setState({ viewOptions: { type: 'bar', stacked: false, column: false } });
        break;
      case 'column':
        this.setState({ viewOptions: { type: 'bar', stacked: false, column: true } });
        break;
      default:
        break;
    }
  }

  optionsDropdown = () => {
    const options = [
      { onClick: () => this.handleChartType('pie'), text: 'Pie' },
      { onClick: () => this.handleChartType('bar'), text: 'Bar' },
      { onClick: () => this.handleChartType('column'), text: 'Column' },
    ];

    return options;
  }

  render() {
    const { chartSeries, viewOptions, title } = this.state;

    return (
      chartSeries.length > 0 &&
      <div className="content" >
        <h4>{title}</h4>
        <div className="box">
          <EffectivenessChart type={viewOptions.type} series={chartSeries} title={title} optionMenu={this.optionsDropdown()} stacked={viewOptions.stacked} column={viewOptions.column} transposed />
        </div>
      </div>
    );
  }
}

ClickEffectivenessChart.propTypes = {
  answersSummary: PropTypes.object, //eslint-disable-line
};

ClickEffectivenessChart.defaultProps = {
  answersSummary: {},
};

export default WithSpinner(ClickEffectivenessChart);

有时,componentWillReceiveProps它没有触发器,我可以看到原因。我假设我的WithSpinner控制器有问题,但我可以看出问题是什么。在使用WithSpinner控制器

包装的所有组件中都会发生相同的行为

请帮忙吗?

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Heatmap from 'components/heatmap';
import ClickEffectivenessChart from './click_effectiveness_chart';
import ClickEffectivenessTable from './click_effectiveness_table';
import AreaChart from './area_chart';
import SctHeatmap from './sct_heatmap';


class SctAnswersSummary extends Component {
  componentDidMount() {
    if (this.props.questionId) { this.fetchData(); }
  }

  componentDidUpdate(prevProps) {
    if (prevProps.questionId !== this.props.questionId) { this.fetchData(); }
  }

  fetchData = () => { 
    const {
      datacenterId, accountId, projectId, questionId,
    } = this.props;
    this.props.actions.questionFetchRequest(datacenterId, accountId, projectId, questionId);
    this.props.actions.answersSummaryFetchRequest(datacenterId, accountId, projectId, questionId);
    this.props.actions.answersSctClicksFetchRequest(datacenterId, accountId, projectId, questionId);
  }

  render() {
    const { imageUrl, clicks, questionId, imageWidth, imageHeight } = this.props.answerSctClicks;
    const { answersSummaryLoading, answersSctLoading, answersSummary } = this.props;

    return (
      <div className="content">
        <div className="content" >
          <SctHeatmap imageUrl={imageUrl} clicks={clicks} questionId={questionId} imageWidth={imageWidth} imageHeight={imageHeight} loading={answersSctLoading} />
          <br />
          <ClickEffectivenessChart answersSummary={answersSummary} loading={answersSummaryLoading} />
          <br />
          <AreaChart answersSummary={answersSummary} loading={answersSummaryLoading} />
          <br />
          <ClickEffectivenessTable answersSummary={answersSummary} loading={answersSummaryLoading} />
        </div>
      </div>
    );
  }
}

SctAnswersSummary.propTypes = {
  datacenterId: PropTypes.string,
  accountId: PropTypes.string,
  projectId: PropTypes.string,
  questionId: PropTypes.string,
  questionSct: PropTypes.object, // eslint-disable-line react/forbid-prop-types
  actions: PropTypes.shape({
    questionSctFetchRequest: PropTypes.func,
  }).isRequired,
  answersSummaryLoading: PropTypes.bool,
  answersSctLoading: PropTypes.bool,
};

SctAnswersSummary.defaultProps = {
  datacenterId: null,
  accountId: null,
  projectId: null,
  questionId: null,
  questionSct: {},
  answersSummaryLoading: true,
  answersSctLoading: true,
};

export default SctAnswersSummary;

1 个答案:

答案 0 :(得分:1)

这是因为您的HOC是一个功能无状态组件,这意味着它没有任何生命周期事件。您需要将WithSpinner转换为类组件,然后生命周期事件应该流入您的包装组件:

const WithSpinner = (WrappedComponent) => {
    return class extends React.Component {
        componentWillReceiveProps(nextProps) {
            console.log('Current props: ', this.props);
            console.log('Next props: ', nextProps);
        }
        render() {
            return <div>
                {this.props.loading ? 
                    <Spinner /> 
                : 
                    <WrappedComponent {...this.props}>
                        {this.props.children}
                    </WrappedComponent>}
            </div>
        }
    }
}