React:从回调中设置功能组件的状态

时间:2021-05-05 00:20:57

标签: reactjs callback react-hooks

我的顶级函数组件 App 有一个返回 Promise 的函数 req(),它将被许多子组件调用。在内部,req() 更新 App 的状态以显示它被调用(以及为什么),然后调用不同的承诺返回函数。这是req()

  //wrap all requests to track and display their progress
  function req(func, args, waitCap, yayCap) {
    
    //perform a callback on a given req, then update state
    const withReq = (argId, callback) => {
      let newReqs = state.reqList.map ( r => r); //copy the reqList

      for (let reqIndex = 0; reqIndex < newReqs.length; reqIndex++) { //iterate through the list
        if ((newReqs[reqIndex] && (newReqs[reqIndex].id === argId))) {  //find a match
          callback(newReqs[reqIndex]);  //pass it to the callback
          break;
        }
      }

      setState( prevState => ({
        ...prevState,
        reqList:newReqs,
      }));
    }

    //kill a req and update state
    const deleteReq = argId => {
      let newReqs = state.reqList.filter( r => {  //new reqList is the same list with no objects containing the argID
        return r.id !== argId;
      });

      setState( prevState => ({
        ...prevState,
        reqList:newReqs,
      }));
    }

    //duplicate the req list
    let newReqs = state.reqList.map( r => r );

    const now = new Date(); //create a unique ID for this req for tracking
    const reqId = [
      now.getFullYear(),
      String(now.getMonth()+1).padStart(2,"0"),
      String(now.getDate()).padStart(2,"0"),
      String(now.getHours()).padStart(2,"0"),
      String(now.getMinutes()).padStart(2,"0"),
      String(now.getSeconds()).padStart(2,"0"),
      String(Math.floor(Math.random()*10000)).padStart(4,"0"),
    ].join("");

    newReqs.push({  //add the new req to the new reqList
      status:"waiting",
      caption:waitCap,
      id:reqId,
    });

    setState( prevState => ({ //render the changed list of Reqs
      ...prevState,
      reqList:newReqs,
    }));

    return ServerCalls[func](args)
    .then((res)=>{        
      withReq(reqId, foundReq =>{ //update the req to show success
        foundReq.status="success";
        foundReq.caption=yayCap;
      });

      setTimeout(() => {
        deleteReq(reqId); //remove it from display after 3 seconds
      }, 3000);
      return res;
    })
    .catch((err)=>{
      withReq(reqId, foundReq =>{ //update the req to show failure
        foundReq.status="failure";
        foundReq.caption=foundReq.caption+" Failed!";
      });
      setTimeout(() => {
        deleteReq(reqId); //remove it from display after 3 seconds
      }, 3000);
      throw err;
    })
  }

这里的问题是 Promise.then()Promise.catch() 中的回调函数对状态的初始值进行操作,而不是由于作用域的原因,它在回调执行时具有的值。这不是类组件的问题,只是功能组件的问题。

有没有办法让功能组件从回调中读取其执行时状态?或者是否需要解决方法?

1 个答案:

答案 0 :(得分:0)

这里有两个问题:

  • 当你这样做时,你正在改变现有的状态
withReq(reqId, foundReq => { //update the req to show success
    foundReq.status = "success";
    foundReq.caption = yayCap;
});

永远不要在 React 中改变状态 - 它会导致重新渲染问题。

  • .then 回调中的值已过时。通过将状态设置器函数中的当前(新更新)状态而不是旧状态传递给 callback 来解决此问题:
const withReq = (argId, callback) => {
    setState(prevState => ({
        ...prevState,
        reqList: prevState.reqList.map(req => (
            req.id === argId ? callback(req) : req
        )),
    }));
}

然后确保 callback 不会变异,而是创建并返回一个新对象,例如:

withReq(reqId, foundReq => ({
    ...foundReq,
    status: "success",
    caption: yayCap,
}));
相关问题