简体   繁体   English

setState 循环遍历一组道具 - React ComponentDidUpdate

[英]setState while looping through an array of props - React ComponentDidUpdate

I am working on a project and needed to setState after componentDidMount.(The props am expecting in the child component are derived at mount. Hence i can only setState after) Only option i was able to come up with was, using componentDidUpdate.我正在做一个项目,需要在 componentDidMount 之后设置状态。(期望子组件中的道具是在挂载时派生的。因此我只能在之后设置状态)我能想出的唯一选项是使用 componentDidUpdate。

The props parent component is an array derived from an axios fetched data. props 父组件是一个从 axios 获取的数据派生的数组。

The goal here is to loop though the array and fetch data for each from the URL showing in the code below to then setState of the child component.这里的目标是遍历数组并从下面代码中显示的 URL 中获取每个数组的数据,然后设置子组件的 setState。

Trying what i normally do, I could not stop the infinite loop fired at componentDidUpdate.尝试我通常做的事情,我无法停止在 componentDidUpdate 处触发的无限循环。

Here is my code.这是我的代码。

Parent家长

  render(){

  return (
    <div className="App">

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

    </div>

Child component子组件

     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]
                    }))  
                })
        })
        }    
    }

console log works perfectly fine.控制台日志工作得很好。 But when i tried to setState, i run into infinite loop with something like 5000 plus error messages.但是当我尝试 setState 时,我遇到了像 5000 条错误消息这样的无限循环。

And my other trick was我的另一个技巧是

 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]
                    }))  
        })
        }    
    }

And this one returns promises and not the needed data.而这个返回的是承诺而不是所需的数据。

Help Fam帮助家庭

What am i missing?我错过了什么?

Your issue is likely caused by derived state: state that is dependent on props and is an anti pattern in react: https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#when-to-use-derived-state Your issue is likely caused by derived state: state that is dependent on props and is an anti pattern in react: https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state .html#when-to-use-derived-state

See below on a plausible workaround, though its recommended you restructure your data flow.请参阅下面的可行解决方法,但建议您重组数据流。

Try something like this to first only send 1 update to state:尝试这样的事情,首先只向 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();
}

If the above doesn't work (which it might not), then use getDerivedStateFromProps instead of componentDidMount and replace setState with a return obj如果上述方法不起作用(可能不起作用),则使用 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; 
}

If that doesn't work, then revert back to componentDidMount and use shouldComponentUpdate for the conditional如果这不起作用,则恢复到 componentDidMount 并使用 shouldComponentUpdate 作为条件

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

Incase I didn't get the syntax just right look at this code snippet如果我没有得到正确的语法,请查看此代码片段

 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();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM