【问题标题】:ReactJS Redux Asynchronous ActionsReactJS Redux 异步操作
【发布时间】:2020-04-23 11:16:00
【问题描述】:

我已经阅读了很多关于在 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) 除了这个弹出消息(自动隐藏)之外,到目前为止我找不到任何其他类似的场景,但是还有其他类似的场景吗?有什么例子吗?

【问题讨论】:

  • 如果我很好地理解了您的问题,那么您的主要问题是,为什么即使组件重新渲染,带有消息"success","uploded" 的模态也会显示?
  • 带有消息的模态显示 bcs UploadStatus 仍然保持值 "Completed" 。我的问题是如何在使用 redux 时处理这种情况。正如我在下面的代码中所示,如何在普通的 reactjs 中简单地处理这个问题(例如,不使用 redux)。我的问题是使用 react 时是否有不同的方法来呈现 UI?当我适应redux时,我的组件渲染方法的逻辑会改变吗?
  • 消息反复弹出的原因是因为你的状态仍然设​​置为完成。通常你会有在一定时间后改变 UploadStatus 的逻辑,或者当用户按下取消按钮但它被合并到你的 ANTD 中时。
  • 我不使用ANTD,但在定时器结束后ANTD是否运行onClose?如果是这样,请发送一个新状态以清除您的 UploadStatus。
  • @Zydnar 根据您的逻辑,javascript 默认情况下应将所有函数视为异步。但是,我敢打赌,每当运行异步函数时,都会添加一些额外的后台逻辑。不使用就不要插入。

标签: javascript reactjs redux redux-thunk react-state-management


【解决方案1】:

具体解决方案

ANTD Message component documentation 提到了一个 onClose(函数)参数,您可以将其传递给控件。

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

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

一般想法

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

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

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

【讨论】:

  • 请看我对这个问题的回答
  • @umer 我已经更新了我的答案,以提供有关组件与 redux 状态主题的一些一般性想法。我想指出的是,SO 是针对具有特定答案的特定问题,并且不赞成用实际上只是对原始问题的澄清的答案来回答您自己的问题。
  • thanx @tex 我赞成你的回答,因为 onClose 事件也是一个解决方案,但我还是以不同的方式解决了它。我也同意你关于 redux 的一般想法,在我的情况下,这个状态属于其他组件,所以我必须保留它。
【解决方案2】:

使用redux

Redux 将 UploadStatus 属性传递给您的组件。在每次渲染(击键等)时,您都使用 UploadStatus 及其各自的 ANTD 渲染消息重新渲染。这会导致 rendermessage 运行多次,因为 rendermessage 使用不正确。

没有redux

没有传递重复渲染的道具。 ANTD的rendermessage只在函数完成后调用一次。

您有多种选择来处理它。

  1. 不要将 ANTD 的渲染消息连接到 UploadStatus。只需按照您在没有 redux 的情况下设置的方式使用它。
  2. 如果你必须使用 redux,创建一个单独的组件来处理它,并创建一个 React 的 useEffect 来触发 rendermessage。

【讨论】:

    猜你喜欢
    • 2017-09-26
    • 2016-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-31
    • 1970-01-01
    相关资源
    最近更新 更多