首页 > 解决方案 > ReactJS Redux 异步操作

问题描述

我已经阅读了很多关于在 reactjs 中使用 redux 的教程,但是我仍然缺少一些东西。下面是我的操作方法

export const uploadFile = (files) => async (dispatch) => {

dispatch({ 
    type: T.UPLOAD_REQUEST,
    payload:{UploadStatus:"InProcess"}
 });
axios.post(`${config.API_URL}/upload`, files)
    .then(res => {
        dispatch({ 
            type: T.UPLOAD_SUCCESS, 
            payload: { UploadResponse: res.data,UploadStatus:"Completed"} 
        });
    }).then(res=>{

        dispatch({ 
            type: T.UPLOAD_SUCCESS, 
            payload: { UploadResponse: null,UploadStatus:"Queued"} 
        });

    })
    .catch(err =>{
        console.log(err);
        dispatch({ 
            type: T.UPLOAD_FAIL, 
            payload: { UploadResponse: err,UploadStatus:"Error" } 

        });
    }
    ).then(res=>{

        dispatch({ 
            type: T.UPLOAD_FAIL, 
            payload: { UploadResponse: null,UploadStatus:"Queued"} 
        });

    })
};

此操作将文件上传到服务器并分派到 reducer 以在 UI 上进行更新。“UploadResponse”和“UploadStatus”是我需要在前端呈现 UI 的两个状态字段。

当请求开始时,我设置{UploadStatus:"InProcess"}为渲染一个微调器。在请求成功或失败后,我将此状态字段相应地设置为“已完成”或“错误”。这有助于我移除微调器并呈现成功或失败消息。

当请求成功并且 UploadStatus 设置为“已完成”并且在前端弹出一条成功消息并且用户在组件上进一步交互以重新呈现组件之后,假设我在文本框中输入了一些文本,会发生什么是 UploadStatus 仍然持有值“已完成”,消息再次弹出。

为了解决这个问题,我对每个成功或失败的请求响应进行 2 次调度。例如,您可以在上面的代码中看到,在呼叫成功时我首先发送 {UploadStatus:"Completed"},然后{UploadStatus:"Queued"}重置状态。它以某种方式帮助我,在第一次调度时,我在屏幕上呈现成功消息,然后我重置上传状态,以便在组件上的进一步交互时不会弹出消息。

但是当 UploadStatus 设置为完成时,我必须在前端呈现一个 div,即使在对组件进行进一步操作之后,这个 div 也必须存在。在我的第二次调度中,UploadStatus 设置为“Queued”,因此 div 消失了。

我将在下面进一步添加我的组件代码来解释我渲染 UI 的逻辑

render() {
  return (
  <div>
   <div className="upload-sect">
   {
      this.props.UploadStatus=="InProcess"?<Spin/>: <></>
      this.props.UploadStatus=="Completed"? 
      this.rendermessage("success","uploded"):<></>
      this.props.UploadStatus=="Error"?this.rendermessage("error","Upload 
      Fail"):<></>
   }
  </div>
  <div>
    {
      this.props.UploadStatus=="Completed"?
      this.renderUploadResponse(this.props.UploadResponse)
      :
      <></>
    }
</div>
</div>)}

下面是我的渲染消息功能

//message is ANTD design control , which pops up message on screen for a 
//while and hides automatically 
rendermessage=(type,displaymessage)=>{

    if(type=="success"){
        message.success(displaymessage)
    } else if(type=="error"){
        message.error(displaymessage)
    }
}

我使用 Antd 消息在屏幕上弹出消息,该消息会在设定的时间间隔后自动隐藏。https://ant.design/components/message/

所以我在这里缺少的是我找不到根据状态变化在前端呈现 UI 的正确方法。

我会在没有 redux 的情况下简单地处理这种情况,就像在那里我将有方法在我的组件内发送请求,并且在成功或失败响应中,我将直接从那里渲染一条消息,而不是设置状态然后渲染基于消息关于状态。

像下面

 uploadFile=(files) =>{
 this.setState({UploadResponse: null,UploadStatus:"InProcess"});
 axios.post(`${config.API_URL}/upload`, files)
 .then(res => {
    this.rendermessage("success","File uploaded successfully.");
    this.setState({UploadResponse: res.data,UploadStatus:"Completed"});

 })
 .catch(err =>{
    this.rendermessage("fail","Failed to uploaded.");
    this.setState({UploadResponse: res.data,UploadStatus:"Completed"});
 }
 )
 }; 

我只是简单地处理了这个场景,因为发送请求的方法在我的组件内部,我只是在单击上传按钮时调用了这个方法。这减少了我的渲染代码,如下所示

  render() {
  return (
  <div>
   <div className="upload-sect">
   {
      this.props.UploadStatus=="InProcess"?<Spin/>: <></>
   }
  </div>
  <div>
    {
      this.props.UploadStatus=="Completed"?
      this.renderUploadResponse(this.props.UploadResponse)
      :
      <></>
    }
</div>
</div>)}

我在 redux 中缺少什么?我认为这是一个非常常见的场景,在 React 应用程序中会发生数千次。所以它应该很容易处理。我缺少的是我找不到使用 redux 的标准方法?

当您决定使用 redux 而不是在组件级别管理状态时,我是否认为您呈现组件的逻辑会有所不同?

你能建议这个问题的标题到底是什么吗?

更新

从下面的评论部分,我发现大多数人不理解我的问题,所以我需要付出更多的努力才能更具体。

我的问题中给定的问题只是我提出的一个案例。可以有不同的解决方法来解决这个问题,我已经采用并解决了其中一个问题,我稍后会谈到,但首先让我强调一下我的问题。

我已经展示了在组件级别管理状态时,我只是非常简单地处理了 UI。例如,在我的异步调用成功或失败时,我只是调用了一个在屏幕上呈现弹出窗口的方法,所以这个弹出窗口没有附加到任何状态更改,而是直接在动作的结果中呈现。无论您使用 ANTD 消息还是任何其他无关紧要的通知提供程序,问题是它必须自动消失(在通知提供程序功能下,通知在一定时间间隔后隐藏)

所以在正常情况下(我在没有redux的情况下调用正常的reactjs)reactjs我可以简单地实现这种行为。例如,在没有任何状态更改的情况下呈现消息,我将自动消失。

但是在redux中我不能让它那么简单。我已经在我的问题中提出了详细信息。

现在我采用什么解决方案来解决这个问题如下

我得出的结论是,要使用 redux 处理它,我必须进行两次调度来处理该场景,我对我的代码做了一个非常小的改动,让我们把它放在下面,这样你们就不会向上滚动重新访问代码了

export const uploadFile = (files) => (dispatch) => {

dispatch({ type: T.UPLOAD_REQUEST,payload:{UploadStatus:"InProcess"}});
axios.post(`${config.API_URL}/upload`, files}).then(res => {            
dispatch({ type: T.UPLOAD_SUCCESS, payload: { UploadResponse:res.data,
UploadStatus:"Completed",MessageToBeDelievered:true} });
}).then(res=>{
dispatch({ type: T.UPLOAD_SUCCESS, 
        payload: { MessageToBeDelievered:false} 
    });
})
.catch(err =>{
    dispatch({ 
        type: T.UPLOAD_FAIL, payload: { UploadResponse:err,
         UploadStatus:"Error",MessageToBeDelievered:true }  
    });
}).then(res=>{

    dispatch({ type: T.UPLOAD_FAIL, 
    payload: {MessageToBeDelievered:false} 
    });

})
};

所以没有大的变化,我只是在成功或失败调用 MessageToBeDelievered 设置为 true 后的第一次调度中保留额外的一点“MessageToBeDelievered”,以便呈现弹出窗口,然后在下一次调度中将其设置为 false 。很简单吧?..我没有在第二次调度中更改 UploadStatus ,因此在成功调用后它的值仍然是“已完成”,即使在第二次调度之后也是如此。所以我需要在成功调用时显示的 div 会出现并停在那里,除非 UploadStatus 再次进入“InProcess”。

没什么大不了。所以再次回到实际问题,我的问题是

(i) 在使用 redux 和不使用它时,我是否需要对我的 UI 渲染逻辑进行不同的思考。bcs 我认为 redux 只是处理状态的另一种方式,它不应该属于我的组件的渲染逻辑,但是它让我想到组件渲染逻辑会发生一些变化,这是我对 redux 所不期望的。

(ii) 除了这个弹出消息(它会自动隐藏),到目前为止我找不到任何其他类似的场景,但是还有其他类似的场景吗?有什么例子吗?

标签: javascriptreactjsreduxredux-thunkreact-state-management

解决方案


具体解决方案

ANTD组件文档提到了一个MessageonClose函数)参数,您可以将其传递给控件。

当组件在您指定的持续时间后关闭时,您传递的onClose函数将被组件调用。Message

您应该传递一个函数,将UploadStatus您的 redux 状态中的属性更新为“已完成”以外的某个值(例如“非活动”)。

一般想法

您不必对所有状态都使用 redux。将组件状态与 redux 混合使用是完全有效的。我倾向于使用组件状态来存储仅与单个组件及其后代和/或短暂状态相关的状态。我将 redux 用于多个组件使用的状态和/或寿命更长的状态。

如果一个组件依赖于 redux 状态,您将必须管理相关的 redux 状态以控制组件在后续渲染中的行为(例如,正如我上面建议的那样)。正如您所指出的,这可能会使某些事情比取决于组件状态的解决方案稍微复杂一些。

我不知道您的具体示例的完整上下文,但是如果其他组件不需要您显示的状态,我会倾向于将其存储在组件状态中。如果其他组件需要该状态,我会将其存储在 redux 中并按照我上面的建议进行管理。


推荐阅读