【问题标题】:setState while looping through an array of props - React ComponentDidUpdate循环遍历一组道具时的 setState - React ComponentDidUpdate
【发布时间】:2020-07-01 15:57:26
【问题描述】:

我正在做一个项目,需要在 componentDidMount 之后设置状态。(期望子组件中的道具是在挂载时派生的。因此我只能在之后设置状态) 我能想到的唯一选择是使用 componentDidUpdate。

props 父组件是一个从 axios 获取的数据派生的数组。

这里的目标是遍历数组并从下面代码中显示的 URL 中为每个数组获取数据,然后设置子组件的 setState。

尝试我通常做的事情,我无法停止在 componentDidUpdate 处触发的无限循环。

这是我的代码。

父母

  render(){

  return (
    <div className="App">

      <EachCountry countryList= {this.state.CountriesList}/>

    </div>

子组件

     async componentDidUpdate(prevProps, prevState, snapshot){
    if(this.state.countryList.length < this.props.countryList.length){
        await this.props.countryList.map(m=>{
                axios ({
                    method:"get",
                    url:`/countryupdate/${m}`
                }).then(res=>{
                    console.log(res.data)
                    this.setState(crntState=>({
                        countryList:[...crntState.countryList, res.data]
                    }))  
                })
        })
        }    
    }

控制台日志运行良好。但是当我尝试 setState 时,我遇到了像 5000 多条错误消息这样的无限循环。

我的另一个技巧是

 async componentDidUpdate(prevProps, prevState, snapshot){
    if(this.state.countryList.length < this.props.countryList.length){
        await this.props.countryList.map(m=>{
                var newdata =  axios ({
                    method:"get",
                    url:`/countryupdate/${m}`
                })
                console.log(newdata)
                    this.setState(crntState=>({
                        countryList:[...crntState.countryList, newdata.data]
                    }))  
        })
        }    
    }

而这个返回的是承诺而不是所需的数据。

帮助家庭

我错过了什么?

【问题讨论】:

  • ComponentDidUpdate 中的 setState 将创建一个无限循环,因为 setState 将更新组件,并且在更新时将调用 ComponentDidUpdate 生命周期方法
  • @GowriPranithBayyana 并根据文档,为避免这种情况,开发人员应将条件语句放在实际 setState 的头部。我做到了。你猜怎么着,我仍然遇到这个循环。你建议我应该怎么做。

标签: javascript reactjs setstate


【解决方案1】:

您的问题可能是由派生状态引起的:状态依赖于道具并且是反应中的反模式: https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#when-to-use-derived-state

请参阅下面的可行解决方法,但建议您重组数据流。

尝试这样的事情,首先只向状态发送 1 个更新:

async componentDidMount(){

  //variable to store new data
  const allNewData = [];
  
  //an async data fetcher
  const getNewData = async(m) => {
    let newData = await axios({
      method: "get",
      url: `/countryupdate/${m}`
    })
    allNewData.push(newData.data);
  }
  
  //an async for loop
  async function updateData() {
    for (const m of countryList) {
      await getNewData(m);
    }
    this.setState(crntState => ({
      countryList: [...crntState.countryList, ...allNewData]
    }))
  }

  await updateData();
}

如果上述方法不起作用(它可能不起作用),则使用 getDerivedStateFromProps 而不是 componentDidMount 并将 setState 替换为 return obj

static getDerivedStateFromProps(props, state) {
  if (this.state.countryList.length < this.props.countryList.length) {
      ...
      return {
        countryList: [...state.countryList, ...allNewData]
      };
     }

     let newState = await updateData();
     return newState; 
}

如果这不起作用,则恢复到 componentDidMount 并使用 shouldComponentUpdate 作为条件

shouldComponentUpdate(nextProps, nextState) {
    return this.state.countryList.length != nextState.countryList.length; 
}

如果我没有正确理解语法,请查看这段代码 sn-p

function mockAxios(m) {
  return new Promise(function(resolve, reject) {
    setTimeout(() => resolve({
      data: `${m}'s data`
    }), 1000)
  });
}

function setState(arr) {
  console.log(arr);
  console.log("state has been set")
}

const countryList = ["A", "B", "C", "D", "E"];
///////////////////////////////////////////////
async function componentDidMount() {

  const allNewData = [];

  async function getNewData(m) {
    let newData = await mockAxios(m);
    allNewData.push(newData.data);
  }

  async function updateData() {
    for (const m of countryList) {
      await getNewData(m);
      console.log("fetching data...")

    }
    setState(allNewData);
  }

  await updateData();
}
componentDidMount();

【讨论】:

    猜你喜欢
    • 2016-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-22
    • 2019-02-04
    相关资源
    最近更新 更多