如何调用使用状态(由另一个函数设置)的函数并更新状态

时间:2019-05-03 06:05:07

标签: javascript reactjs

我有两个函数,一个函数从api提取数据并根据该数据更新状态,另一个函数是在状态中的数据上进行发送并用新数据更新状态。

我的问题是我无法更新第二个功能的状态。而且我不知道我必须在哪里调用此函数才能在第一个函数之后调用它并使用处于状态的数据。

export default class Cases extends Component {
    constructor(props) {
        super(props);
        this.state = {
            cases: [],
            photos: [],
        };

        this.addPhotos = this.addPhotos.bind(this);
        this.getCases = this.getCases.bind(this);
        this.renderCases = this.renderCases.bind(this);
    }

    getCases() {
        axios
            .get('/cases/api')
            .then(response => {
                this.setState({
                    cases: response.data.cases,
                    photos: response.data.photos,
                });
                console.log(this.state.cases);
            })
            .catch((error) => {
                if (error) {
                    console.log(error);
                }
            });
    }

    addPhotos() {
        const newCases = this.state.cases.map(({ photo_id, ...rest }) => {
            const obj = { ...rest };
            this.state.photos.find(data => {
                if (data.id === photo_id) {
                    obj.file = data.file;
                    return true;
                }
            });
            return obj;
        });

        console.log(this.state.cases);

        this.setState({
          'cases' : newCases
        });

    }

    renderCases() {
        this.addPhotos();
    }

    componentWillMount() {
        this.getCases();
    }


    render() {
        return (
            <div>
              {this.renderCases()}
           </div>
        )
    }
}

这就是我现在拥有的

我应该在哪里调用addPhotos函数,以便它可以更新状态并仍然使用getCases函数中的现有状态数据?

谢谢!

2 个答案:

答案 0 :(得分:1)

所以,第一件事是第一位。生命周期方法componentWillMount()即将被弃用,并且被认为不安全。您应该使用componentDidMount()。

只要在addPhotos函数中使用更新状态,就可以将setState传递给回调函数。一个看似简单的解决方案是将addPhotos函数作为回调传递到在getCases函数中调用的setState中。

 getCases() {
        axios
            .get('/cases/api')
            .then(response => {
                this.setState({
                    cases: response.data.cases,
                    photos: response.data.photos,
                }, this.addPhotos);
                console.log(this.state.cases);
            })
            .catch((error) => {
                if (error) {
                    console.log(error);
                }
            });
    }

另一种解决方案是改为从componentDidUpdate调用addPhotos()。

希望这会有所帮助!

编辑:这只是来自React文档的一些其他背景信息。

  

将setState()视为请求而不是立即命令来更新组件。为了获得更好的感知性能,React可能会延迟它,然后在一次通过中更新几个组件。 React不能保证状态更改会立即应用。

     

setState()并不总是立即更新组件。它可能会批量更新或将更新推迟到以后。这使得在调用setState()之后立即读取this.state可能是一个陷阱。而是使用componentDidUpdate或setState回调(setState(updater,callback)),确保在应用更新后均能触发这两种方法。如果需要基于先前的状态来设置状态,请阅读以下有关updater参数的信息。

答案 1 :(得分:0)

在代码中添加了一些重构,现在应该可以正常工作,请阅读注释以获取详细信息

export default class Cases extends Component {
  constructor(props) {
    super(props);
    this.state = {
      cases: [],
      photos: [],
    };

    this.addPhotos = this.addPhotos.bind(this);
    this.getCases = this.getCases.bind(this);
    this.renderCases = this.renderCases.bind(this);
  }

  getCases() {
    axios
      .get('/cases/api')
      .then(this.addPhotos) // don't need to set state, pass data to consumer function
      .catch(console.error); // catch always gives error, don't need to check with if statement
  }

  addPhotos(response) {
    const cases = response.data.cases // extract values
    const photos = response.data.photos // extract values
    
    // your .map iterator has O^2 complexity (run each item of cases on each item of photos)
    // this new .map iterator has O complexity (run each item of cases)
    const newCases = cases.map(({ photo_id, ...rest }) => {
      const obj = {...rest};
      const data = photos.find(item => item.id === photo_id);
      if (data) {
        obj.file = data.file
      }
      return obj;
    });

    this.setState({
      cases: newCases,
      photos
    });

  }

  componentDidMount() { // better use didMount
    this.getCases();
  }


  render() {
    return (<div />)
  }
}