【问题标题】:Redux is run first首先运行 Redux
【发布时间】:2021-08-02 12:02:41
【问题描述】:

我正在使用 redux 来管理我的应用的全局状态。

我有全局状态“shop”并通过“onFilterShops”改变它的值。

const mapStateToProps = ({ shops }) => {
    return {
        shops: shops.shops
    }
}

const mapDispatchToProps = dispatch => {
    return {
        onFilterShops: shop => dispatch(filterShops(shop))
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(MenuShop)

更改此状态会在我的应用中运行一个过滤器并需要几秒钟,因此我想在此过程中显示一个 Spinner。

const toggleMenu = index => {
        setIsLoading(true) //Local state, Spinner visible - Line 1
        props.onFilterShops(index) // Line 2
        setIsLoading(false) //Local state, Spinner invisible - Line 3
    }

问题是执行第一行2,过滤器完成,在过滤器结束时,执行第1行和第3行,Spinner没有机会出现。

如果我在中间放一个承诺,它会起作用,但它很丑。

const wait = ms => new Promise(resolve => setTimeout(resolve, ms))
const toggleMenu = async (index) => {
        setIsLoading(true)
        await wait(1)
        props.onFilterShops(index)
        setIsLoading(false)
    }

为什么?

【问题讨论】:

  • 如果 Promise 丑陋,不要使用 javascript。有一些选择:例如 Kotlin/JS 和 React。在这里,您可以使用 Curutines。它们非常简洁且富有表现力。哪个海豚在这里有 1 秒的延迟?
  • 嗨@BierDav。丑陋的不是承诺,而是我所做的。我创建了一个承诺,在执行过滤器之前等待 1 毫秒。这是丑陋的,它必须有一个更优雅的方式。
  • 有道理

标签: javascript node.js react-native react-redux


【解决方案1】:

您可以将调度操作视为应用程序中的“触发事件”。

您在第 2 行执行的函数只会调度操作,因此它不会等待代码运行。

由于这个原因,第 3 行被立即触发,看起来你的加载微调器从未出现过。

有几种方法可以实现您想要的功能,例如通过redux thunk,假设代码是异步的。

我认为学习 redux 基础知识是一个很好的起点。

【讨论】:

  • 你能举个例子吗?
  • 我没有任何异步进程。我只是设置了一个本地状态(setIsLoading)来显示 Spinner,更改全局状态(props.onFilterShops)并再次设置本地状态(setIsLoading)以与 Spinner 一起消失。
  • 如果没有异步逻辑,也许你不需要加载微调器?如果您将全局状态设置为本地列表/变量,您甚至不会看到状态更改,因为它发生的速度非常快。
  • 我不认为它与redux有任何关系。我将我的问题简化为:stackoverflow.com/questions/68627714/…
  • 当我更改全局状态时,我的 UI 被渲染,并且各种组件基于该全局状态渲染,这需要时间,所以我需要一个指示器 @Robin Claes
【解决方案2】:

问题

在第 1 行中,您计划更新状态,但之后您立即阻塞了整个线程,因此 redux 没有机会更新 ui,直到繁重的负载结束。当负载结束时,您已经将状态设置回其原始状态。

解决方案

根据这个线程,你必须调度 setIsLoading 函数:React Loading Spinner + Redux?

也看看promise:https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Promise

简单用法:

const [isLoading, setIsLoading] = useState(false)
let computationResult = "Hello World!"

function someLoadingFunction(){
   dispatch(setIsLoading(true))
   new Promise<string>((resolve, reject) => {
      //Do your filtering
      return "this result took really long and baked your cpu"
   }.then((result) => {
      computationResult = result
      dispatch(setIsLoading(false))
   }
   
}

someLoadingFunction()
console.log(computationResult)

希望你能理解;)

如果有帮助:将我的答案标记为已回答。目前我想获得更多的声誉;)

如果还有什么问题:欢迎评论

【讨论】:

  • 嗨@BierDav,我正在实施你的帮助,我会回答你的。谢谢
  • 没用,Spinner 不退出,只在过滤器完成后运行。
  • const toggleMenu = index => { setIsLoading(true) new Promise((resolve, reject) => { props.onFilterShops(index) return "这个结果花了很长时间并且烤了你的 cpu" }) .then(result => { setIsLoading(false) }) .catch(console.log) }
  • 等我看看
  • 我无法评估这个问题。你能给我一个我可以运行的完整示例吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-12-21
  • 2012-03-12
  • 1970-01-01
  • 2018-01-02
  • 2018-11-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多