Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
293 views
in Technique[技术] by (71.8m points)

javascript - 如何使用超时调度Redux操作?(How to dispatch a Redux action with a timeout?)

I have an action that updates notification state of my application.

(我有一个更新我的应用程序的通知状态的操作。)

Usually, this notification will be an error or info of some sort.

(通常,此通知将是某种错误或信息。)

I need to then dispatch another action after 5 seconds that will return the notification state to initial one, so no notification.

(我需要在5秒后发送另一个操作,将通知状态返回到初始状态,因此不会发出通知。)

The main reason behind this is to provide functionality where notifications disappear automatically after 5 seconds.

(这背后的主要原因是提供通知在5秒后自动消失的功能。)

I had no luck with using setTimeout and returning another action and can't find how this is done online.

(我没有运气使用setTimeout并返回另一个动作,但无法找到如何在线完成。)

So any advice is welcome.

(所以欢迎任何建议。)

  ask by Ilja translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Don't fall into the trap of thinking a library should prescribe how to do everything .

(不要陷入认为图书馆应该规定如何做所有事情陷阱 。)

If you want to do something with a timeout in JavaScript, you need to use setTimeout .

(如果您想在JavaScript中执行超时操作,则需要使用setTimeout 。)

There is no reason why Redux actions should be any different.

(没有理由认为Redux的行为应该有所不同。)

Redux does offer some alternative ways of dealing with asynchronous stuff, but you should only use those when you realize you are repeating too much code.

(Redux 确实提供了一些处理异步内容的替代方法,但是只有在意识到重复代码太多时才应该使用它们。)

Unless you have this problem, use what the language offers and go for the simplest solution.

(除非您遇到此问题,否则请使用语言提供的内容并选择最简单的解决方案。)

Writing Async Code Inline(编写异步代码内联)

This is by far the simplest way.

(这是迄今为止最简单的方法。)

And there's nothing specific to Redux here.

(这里没有Redux特有的东西。)

store.dispatch({ type: 'SHOW_NOTIFICATION', text: 'You logged in.' })
setTimeout(() => {
  store.dispatch({ type: 'HIDE_NOTIFICATION' })
}, 5000)

Similarly, from inside a connected component:

(同样,从连接组件内部:)

this.props.dispatch({ type: 'SHOW_NOTIFICATION', text: 'You logged in.' })
setTimeout(() => {
  this.props.dispatch({ type: 'HIDE_NOTIFICATION' })
}, 5000)

The only difference is that in a connected component you usually don't have access to the store itself, but get either dispatch() or specific action creators injected as props.

(唯一的区别是,在连接组件中,您通常无法访问商店本身,但可以将dispatch()或特定操作创建者注入为道具。)

However this doesn't make any difference for us.

(然而,这对我们没有任何影响。)

If you don't like making typos when dispatching the same actions from different components, you might want to extract action creators instead of dispatching action objects inline:

(如果您不喜欢在从不同组件调度相同操作时输入拼写错误,则可能需要提取操作创建器,而不是内联调度操作对象:)

// actions.js
export function showNotification(text) {
  return { type: 'SHOW_NOTIFICATION', text }
}
export function hideNotification() {
  return { type: 'HIDE_NOTIFICATION' }
}

// component.js
import { showNotification, hideNotification } from '../actions'

this.props.dispatch(showNotification('You just logged in.'))
setTimeout(() => {
  this.props.dispatch(hideNotification())
}, 5000)

Or, if you have previously bound them with connect() :

(或者,如果您之前使用connect()绑定它们:)

this.props.showNotification('You just logged in.')
setTimeout(() => {
  this.props.hideNotification()
}, 5000)

So far we have not used any middleware or other advanced concept.

(到目前为止,我们还没有使用任何中间件或其他高级概念。)

Extracting Async Action Creator(提取异步动作创建器)

The approach above works fine in simple cases but you might find that it has a few problems:

(上述方法在简单的情况下工作正常,但您可能会发现它有一些问题:)

  • It forces you to duplicate this logic anywhere you want to show a notification.

    (它会强制您在要显示通知的任何位置复制此逻辑。)

  • The notifications have no IDs so you'll have a race condition if you show two notifications fast enough.

    (通知没有ID,因此如果您足够快地显示两个通知,则会出现竞争条件。)

    When the first timeout finishes, it will dispatch HIDE_NOTIFICATION , erroneously hiding the second notification sooner than after the timeout.

    (当第一个超时完成时,它将调度HIDE_NOTIFICATION ,错误地比超时后错误地隐藏第二个通知。)

To solve these problems, you would need to extract a function that centralizes the timeout logic and dispatches those two actions.

(要解决这些问题,您需要提取一个集中超时逻辑并调度这两个操作的函数。)

It might look like this:

(它可能看起来像这样:)

// actions.js
function showNotification(id, text) {
  return { type: 'SHOW_NOTIFICATION', id, text }
}
function hideNotification(id) {
  return { type: 'HIDE_NOTIFICATION', id }
}

let nextNotificationId = 0
export function showNotificationWithTimeout(dispatch, text) {
  // Assigning IDs to notifications lets reducer ignore HIDE_NOTIFICATION
  // for the notification that is not currently visible.
  // Alternatively, we could store the timeout ID and call
  // clearTimeout(), but we’d still want to do it in a single place.
  const id = nextNotificationId++
  dispatch(showNotification(id, text))

  setTimeout(() => {
    dispatch(hideNotification(id))
  }, 5000)
}

Now components can use showNotificationWithTimeout without duplicating this logic or having race conditions with different notifications:

(现在组件可以使用showNotificationWithTimeout而不复制此逻辑或具有不同通知的竞争条件:)

// component.js
showNotificationWithTimeout(this.props.dispatch, 'You just logged in.')

// otherComponent.js
showNotificationWithTimeout(this.props.dispatch, 'You just logged out.')    

Why does showNotificationWithTimeout() accept dispatch as the first argument?

(为什么showNotificationWithTimeout()接受dispatch作为第一个参数?)

Because it needs to dispatch actions to the store.

(因为它需要将操作分派给商店。)

Normally a component has access to dispatch but since we want an external function to take control over dispatching, we need to give it control over dispatching.

(通常,组件可以访问dispatch但由于我们希望外部函数控制调度,因此我们需要控制调度。)

If you had a singleton store exported from some module, you could just import it and dispatch directly on it instead:

(如果您有从单个模块导出的单件商店,您只需导入它并直接在其上dispatch :)

// store.js
export default createStore(reducer)

// actions.js
import store from './store'

// ...

let nextNotificationId = 0
export function showNotificationWithTimeout(text) {
  const id = nextNotificationId++
  store.dispatch(showNotification(id, text))

  setTimeout(() => {
    store.dispatch(hideNotification(id))
  }, 5000)
}

// component.js
showNotificationWithTimeout('You just logged in.')

// otherComponent.js
showNotificationWithTimeout('You just logged out.')    

This looks simpler but we don't recommend this approach .

(这看起来更简单,但我们不建议采用这种方法 。)

The main reason we dislike it is because it forces store to be a singleton .

(我们不喜欢它的主要原因是因为它迫使商店成为单身人士 。)

This makes it very hard to implement server rendering .

(这使得实现服务器呈现非常困难。)

On the server, you will want each request to have its own store, so that different users get different preloaded data.

(在服务器上,您将希望每个请求都有自己的存储,以便不同的用户获得不同的预加载数据。)

A singleton store also makes testing harder.

(单身商店也使测试更加困难。)

You can no longer mock a store when testing action creators because they reference a specific real store exported from a specific module.

(在测试动作创建者时,您不能再模拟商店,因为它们引用从特定模块导出的特定实体商店。)

You can't even reset its state from outside.

(你甚至无法从外面重置它的状态。)

So while you technically can export a singleton store from a module, we discourage it.

(因此,虽然您在技术上可以从模块导出单件商店,但我们不鼓励它。)

Don't do this unless you are sure that your app will never add server rendering.

(除非您确定您的应用永远不会添加服务器渲染,否则不要这样做。)

Getting back to the previous version:

(回到以前的版本:)

// actions.js

// ...

let nextNotificationId = 0
export function showNotificationWithTimeout(dispatch, text) {
  const id = nextNotificationId++
  dispatch(showNotification(id, text))

  setTimeout(() => {
    dispatch(hideNotification(id))
  }, 5000)
}

// component.js
showNotificationWithTimeout(this.props.dispatch, 'You just logged in.')

// otherComponent.js
showNotificationWithTimeout(this.props.dispatch, 'You just logged out.')    

This solves the problems with duplication of logic and saves us from race conditions.

(这解决了重复逻辑的问题,并使我们免于竞争条件。)

Thunk Middleware(Thunk中间件)

For simple apps, the approach should suffice.

(对于简单的应用程序,该方法应该足够了。)

Don't worry about middleware if you're happy with it.

(如果您对它感到满意,请不要担心中间件。)

In larger apps, however, you might find certain inconveniences around it.

(但是,在较大的应用中,您可能会发现一些不便之处。)

For example, it seems unfortunate that we have to pass dispatch around.

(例如,我们不得不通过dispatch似乎很不幸。)

This makes it trickier to separate container and presentational components because any component that dispatches Redux actions asynchronously in the manner above has to accept dispatch as a prop so it can pass it further.

(这使得分离容器和表示组件变得更加棘手,因为以上述方式异步调度Redux操作的任何组件都必须接受dispatch作为prop,以便它可以进一步传递它。)

You can't just bind action creators with connect() anymore because showNotificationWithTimeout() is not really an action creator.

(你不能再仅仅使用connect()绑定动作创建者,因为showNotificationWithTimeout()实际上不是动作创建者。)

It does not return a Redux action.

(它不会返回Redux操作。)

In addition, it can be awkward to remember which functions are synchronous action creators like showNotification() and which are asynchronous helpers like showNotificationWithTimeout() .

(另外,记住哪些函数是showNotification()等同步动作创建者以及showNotification()类的异步助手可能showNotificationWithTimeout() 。)

You have to use them differently and be careful not to mistake them with each other.

(你必须以不同的方式使用它们,并注意不要互相误解。)

This was the motivation for finding a way to “legitimize” this pattern of providing dispatch to a helper function, and help Redux “see” such asynchronous action creators as a special case of normal action creators rather than totally different functions.

(这是寻找一种方法来“合理化”这种向辅助函数提供dispatch的方式的动机,并帮助Redux“看到”这样的异步动作创建者作为正常动作创建者的特例而不是完全不同的函数。)

If you're still with us and you also recognize as a problem in your app, you are welcome to u


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...