代码之家  ›  专栏  ›  技术社区  ›  Arslan Tariq

这当父级状态必须由子级更新时,setState不起作用

  •  4
  • Arslan Tariq  · 技术社区  · 6 年前

    所以我的应用程序中有一个父组件和一个子组件。我想通过子组件更新父组件的状态,但它似乎不起作用。我已经在Reactjs上工作了很长时间,这对我来说很奇怪。以下是我的父组件代码:

    import React from 'react';
    import { Stage } from 'react-konva';
    import CircleComponent from './CircleComponent';
    import LineComponent from './LineComponent';
    import { getUserPlan } from '../../assets/UserPlan';
    import { addColorClasses } from '../../helpers/utils';
    
    class PortfolioMix extends React.Component {
      constructor(props) {
        super(props);
    
        const data = addColorClasses(getUserPlan().plans[0]);
    
        this.state = {
          data: data,
          circlePoints: []
        };
    
        this.getCirclePoints = this.getCirclePoints.bind(this);
      }
    
      getCirclePoints(points) {
        this.setState({
          circlePoints: points,
          word: 'hello'
        }, () => { console.log(this.state); });
      }
    
      processData() {
        let data = this.state.data;
    
        if(data[0].weight > 0.25 || (data[0].weight+data[1].weight) > 0.67) {
          for(let i = 0; i < data.length; i++) {
            data[i].weight /= 3;
          }
        }
    
        return data;
      }
    
      render() {
        const processedData = this.processData();
        const firstCircle = processedData.splice(0,1);
        const pmData = processedData.splice(0,this.state.data.length);
    
        return(
          <div>
            <Stage
              height={800}
              width={1200}
              style={{ backgroundColor: '#fff'}}>
              <CircleComponent
                x={1200/2}
                y={800/2}
                outerRadius={firstCircle[0].weight*1200}
                outerColor={firstCircle[0].outerColor}
                innerRadius={firstCircle[0].weight*1200*0.3}
                innerColor={firstCircle[0].innerColor}
                shadowColor={firstCircle[0].innerColor}
                getCirclePoints={this.getCirclePoints}
              />
            </Stage>
          </div>
        );
      }
    }
    
    export default PortfolioMix;
    

    下面是子组件的代码:

    class CircleComponent extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          points: this.getPoints(),
        };
      }
    
      componentDidMount() {
        this.props.getCirclePoints(this.state.points);
      }
    
      getPoints() {
        const radius = this.props.outerRadius;
        const x = this.props.x;
        const y = this.props.y;
    
        const points = [];
        let angle = 0;
    
        for(let i = 0; i < 8; i++) {
          points.push({
            pointX: x + radius * Math.cos(-angle * Math.PI / 180),
            pointY: y + radius * Math.sin(-angle * Math.PI / 180)
          });
          angle += 42.5;
        }
    
        return points;
      }
    
      render() {
        const {
          x,
          y,
          outerRadius,
          outerColor,
          shadowColor,
          innerRadius,
          innerColor
        } = this.props;
    
        return (
          <Layer>
            <Group>
              <Circle
                x={x}
                y={y}
                radius={outerRadius}
                fill={outerColor}
                shadowBlur={5}
                shadowColor={shadowColor}
              />
              <Circle
                x={x}
                y={y}
                radius={innerRadius}
                fill={innerColor}
              />
            </Group>
          </Layer>
        );
      }
    }
    
    CircleComponent.propTypes = {
      x: propTypes.number.isRequired,
      y: propTypes.number.isRequired,
      outerRadius: propTypes.number.isRequired,
      outerColor: propTypes.string.isRequired,
      shadowColor: propTypes.string,
      innerRadius: propTypes.number.isRequired,
      innerColor: propTypes.string.isRequired,
      getCirclePoints: propTypes.func
    };
    
    export default CircleComponent;
    

    现在,在父组件中 getCirclePoints 方法,我从孩子那里得到了分数,但是 this.setState 不起作用。如你们所见,我还将一个函数传递给 这设置状态 回调,它不会被调用,也不会设置 data

    2 回复  |  直到 6 年前
        1
  •  2
  •   morganfree    6 年前

    在React文档中,您可以看到不应直接修改状态,而只能使用 setState() 方法您确实修改了 PorfolioMix 直接陈述两次:

    1. 在里面 processData :

      data[i].weight /= 3;
      
    2. 在里面 render :

      const processedData = this.processData();
      const firstCircle = processedData.splice(0,1);
      const pmData = processedData.splice(0,this.state.data.length);
      

    因为 提供 代码中的方法至少被调用两次, this.state.data 将是一个导致错误的空数组。

    您可以在此处看到一个带有错误的实时示例: https://jsfiddle.net/rhapLetv/

    要修复它,您可以在 处理数据 方法:

    processData() {
      const data = this.state.data;
    
      if(data[0].weight > 0.25 || (data[0].weight+data[1].weight) > 0.67) {
        return data.map(point => ({ ...point, weight: point.weight / 3 }))
      } else {
        return data.slice()
      }
    }
    

    修复实例: https://jsfiddle.net/rhapLetv/1/

    immutable.js (或类似的库/助手)引入不可变数据。

        2
  •  0
  •   Maurício Reatto Duarte    6 年前

    你需要 .bind(this) at方法 processData()

    class PortfolioMix extends React.Component {
      constructor(props) {
        super(props);
    
        const data = addColorClasses(getUserPlan().plans[0]);
    
        this.state = {
          data: data,
          circlePoints: []
        };
    
        this.getCirclePoints = this.getCirclePoints.bind(this);
        this.processData = this.processData.bind(this);
      }
    // ...