我有一个更新应用程序通知状态的操作。通常,该通知将是一个错误或某种类型的信息。然后,我需要在5秒后分派另一个动作,将通知状态返回到初始状态,因此没有通知。这背后的主要原因是提供通知在5秒后自动消失的功能。
我没有运气使用setTimeout和返回另一个动作,无法找到这是如何在线完成的。所以任何建议都是欢迎的。
我有一个更新应用程序通知状态的操作。通常,该通知将是一个错误或某种类型的信息。然后,我需要在5秒后分派另一个动作,将通知状态返回到初始状态,因此没有通知。这背后的主要原因是提供通知在5秒后自动消失的功能。
我没有运气使用setTimeout和返回另一个动作,无法找到这是如何在线完成的。所以任何建议都是欢迎的。
当前回答
我知道这个问题有点老了,但我将介绍另一种解决方案,使用还原可观测。史诗。
引用官方文件:
什么是可还原可观察?
基于RxJS 5的Redux中间件。合成和取消异步操作 创造副作用等等。
史诗是还原可观察的核心原语。
它是一个接受操作流并返回流的函数 的行动。行动进,行动出。
简而言之,您可以创建一个通过流接收操作的函数,然后返回一个新的操作流(使用常见的副作用,如超时、延迟、间隔和请求)。
让我发布代码,然后再详细解释一下
store.js
import {createStore, applyMiddleware} from 'redux'
import {createEpicMiddleware} from 'redux-observable'
import {Observable} from 'rxjs'
const NEW_NOTIFICATION = 'NEW_NOTIFICATION'
const QUIT_NOTIFICATION = 'QUIT_NOTIFICATION'
const NOTIFICATION_TIMEOUT = 2000
const initialState = ''
const rootReducer = (state = initialState, action) => {
const {type, message} = action
console.log(type)
switch(type) {
case NEW_NOTIFICATION:
return message
break
case QUIT_NOTIFICATION:
return initialState
break
}
return state
}
const rootEpic = (action$) => {
const incoming = action$.ofType(NEW_NOTIFICATION)
const outgoing = incoming.switchMap((action) => {
return Observable.of(quitNotification())
.delay(NOTIFICATION_TIMEOUT)
//.takeUntil(action$.ofType(NEW_NOTIFICATION))
});
return outgoing;
}
export function newNotification(message) {
return ({type: NEW_NOTIFICATION, message})
}
export function quitNotification(message) {
return ({type: QUIT_NOTIFICATION, message});
}
export const configureStore = () => createStore(
rootReducer,
applyMiddleware(createEpicMiddleware(rootEpic))
)
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import {configureStore} from './store.js'
import {Provider} from 'react-redux'
const store = configureStore()
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
App.js
import React, { Component } from 'react';
import {connect} from 'react-redux'
import {newNotification} from './store.js'
class App extends Component {
render() {
return (
<div className="App">
{this.props.notificationExistance ? (<p>{this.props.notificationMessage}</p>) : ''}
<button onClick={this.props.onNotificationRequest}>Click!</button>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
notificationExistance : state.length > 0,
notificationMessage : state
}
}
const mapDispatchToProps = (dispatch) => {
return {
onNotificationRequest: () => dispatch(newNotification(new Date().toDateString()))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App)
解决这个问题的关键代码就像你看到的一样简单,唯一与其他答案不同的是rootpic函数。
点1。与saga一样,为了获得一个顶级函数来接收动作流并返回动作流,您必须将这些epics组合在一起,因此可以将它与中间件工厂createEpicMiddleware一起使用。在我们的例子中,我们只需要一个,所以我们只有rootEpic,所以我们不需要组合任何东西,但知道事实是很好的。
点2。我们的rootEpic只需要5行代码就可以处理副作用,这太棒了!包括这几乎是声明性的事实!
点3。逐行解析(在注释中)
const rootEpic = (action$) => {
// sets the incoming constant as a stream
// of actions with type NEW_NOTIFICATION
const incoming = action$.ofType(NEW_NOTIFICATION)
// Merges the "incoming" stream with the stream resulting for each call
// This functionality is similar to flatMap (or Promise.all in some way)
// It creates a new stream with the values of incoming and
// the resulting values of the stream generated by the function passed
// but it stops the merge when incoming gets a new value SO!,
// in result: no quitNotification action is set in the resulting stream
// in case there is a new alert
const outgoing = incoming.switchMap((action) => {
// creates of observable with the value passed
// (a stream with only one node)
return Observable.of(quitNotification())
// it waits before sending the nodes
// from the Observable.of(...) statement
.delay(NOTIFICATION_TIMEOUT)
});
// we return the resulting stream
return outgoing;
}
我希望这能有所帮助!
其他回答
Redux操作只能返回一个普通对象,而不是函数、回调或异步进程。为了通过web API(如timeout()方法)分派它们,你必须使用redux-thunk中间件。创建它是为了处理这样的流程。
首先通过文档配置redux-thunk 第二,这样改变你的动作创建器:
const yourAction = millisecond => dispatch => {
setTimeout(() => {
dispatch({
type: 'YOUR_ACTIION_TYPE',
payload: yourWhatEverPayload
})
}, millisecond)
}
你可以用redux-thunk做到这一点。redux文档中有关于setTimeout等异步操作的指南。
在尝试了各种流行的方法(动作创造者,坦克,传奇,史诗,效果,自定义中间件)后,我仍然觉得可能还有改进的空间,所以我在这篇博客文章中记录了我的旅程,在React/Redux应用程序中我应该把我的业务逻辑放在哪里?
就像这里的讨论一样,我尝试对比和比较各种方法。最终,我引入了一个新的redux-logic库,它的灵感来自史诗、传奇故事和自定义中间件。
它允许您拦截验证、验证、授权的操作,并提供了一种执行异步IO的方法。
一些常见的功能可以简单地声明,如debashing、节流、取消,并且只使用来自最新请求的响应(takeLatest)。Redux-logic包装为您提供此功能的代码。
这使您可以随心所欲地实现核心业务逻辑。除非你愿意,否则你不必使用可观察对象或生成器。使用函数和回调,承诺,异步函数(async/await)等。
做一个简单的5s通知的代码是这样的:
const notificationHide = createLogic({ // the action type that will trigger this logic type: 'NOTIFICATION_DISPLAY', // your business logic can be applied in several // execution hooks: validate, transform, process // We are defining our code in the process hook below // so it runs after the action hit reducers, hide 5s later process({ getState, action }, dispatch) { setTimeout(() => { dispatch({ type: 'NOTIFICATION_CLEAR' }); }, 5000); } });
在我的repo中,我有一个更高级的通知示例,其工作原理类似于Sebastian Lorber所描述的,您可以将显示限制为N个项目,并通过任何排队的项目进行旋转。Redux-logic通知示例
我有各种redux-logic jsfiddle现场的例子,以及完整的例子。我还在继续写文档和例子。
我很想听听你的反馈。
这很简单。使用trim-redux包,在componentDidMount或其他地方这样写,并在componentWillUnmount中杀死它。
componentDidMount() {
this.tm = setTimeout(function() {
setStore({ age: 20 });
}, 3000);
}
componentWillUnmount() {
clearTimeout(this.tm);
}
我知道这个问题有点老了,但我将介绍另一种解决方案,使用还原可观测。史诗。
引用官方文件:
什么是可还原可观察?
基于RxJS 5的Redux中间件。合成和取消异步操作 创造副作用等等。
史诗是还原可观察的核心原语。
它是一个接受操作流并返回流的函数 的行动。行动进,行动出。
简而言之,您可以创建一个通过流接收操作的函数,然后返回一个新的操作流(使用常见的副作用,如超时、延迟、间隔和请求)。
让我发布代码,然后再详细解释一下
store.js
import {createStore, applyMiddleware} from 'redux'
import {createEpicMiddleware} from 'redux-observable'
import {Observable} from 'rxjs'
const NEW_NOTIFICATION = 'NEW_NOTIFICATION'
const QUIT_NOTIFICATION = 'QUIT_NOTIFICATION'
const NOTIFICATION_TIMEOUT = 2000
const initialState = ''
const rootReducer = (state = initialState, action) => {
const {type, message} = action
console.log(type)
switch(type) {
case NEW_NOTIFICATION:
return message
break
case QUIT_NOTIFICATION:
return initialState
break
}
return state
}
const rootEpic = (action$) => {
const incoming = action$.ofType(NEW_NOTIFICATION)
const outgoing = incoming.switchMap((action) => {
return Observable.of(quitNotification())
.delay(NOTIFICATION_TIMEOUT)
//.takeUntil(action$.ofType(NEW_NOTIFICATION))
});
return outgoing;
}
export function newNotification(message) {
return ({type: NEW_NOTIFICATION, message})
}
export function quitNotification(message) {
return ({type: QUIT_NOTIFICATION, message});
}
export const configureStore = () => createStore(
rootReducer,
applyMiddleware(createEpicMiddleware(rootEpic))
)
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import {configureStore} from './store.js'
import {Provider} from 'react-redux'
const store = configureStore()
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
App.js
import React, { Component } from 'react';
import {connect} from 'react-redux'
import {newNotification} from './store.js'
class App extends Component {
render() {
return (
<div className="App">
{this.props.notificationExistance ? (<p>{this.props.notificationMessage}</p>) : ''}
<button onClick={this.props.onNotificationRequest}>Click!</button>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
notificationExistance : state.length > 0,
notificationMessage : state
}
}
const mapDispatchToProps = (dispatch) => {
return {
onNotificationRequest: () => dispatch(newNotification(new Date().toDateString()))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App)
解决这个问题的关键代码就像你看到的一样简单,唯一与其他答案不同的是rootpic函数。
点1。与saga一样,为了获得一个顶级函数来接收动作流并返回动作流,您必须将这些epics组合在一起,因此可以将它与中间件工厂createEpicMiddleware一起使用。在我们的例子中,我们只需要一个,所以我们只有rootEpic,所以我们不需要组合任何东西,但知道事实是很好的。
点2。我们的rootEpic只需要5行代码就可以处理副作用,这太棒了!包括这几乎是声明性的事实!
点3。逐行解析(在注释中)
const rootEpic = (action$) => {
// sets the incoming constant as a stream
// of actions with type NEW_NOTIFICATION
const incoming = action$.ofType(NEW_NOTIFICATION)
// Merges the "incoming" stream with the stream resulting for each call
// This functionality is similar to flatMap (or Promise.all in some way)
// It creates a new stream with the values of incoming and
// the resulting values of the stream generated by the function passed
// but it stops the merge when incoming gets a new value SO!,
// in result: no quitNotification action is set in the resulting stream
// in case there is a new alert
const outgoing = incoming.switchMap((action) => {
// creates of observable with the value passed
// (a stream with only one node)
return Observable.of(quitNotification())
// it waits before sending the nodes
// from the Observable.of(...) statement
.delay(NOTIFICATION_TIMEOUT)
});
// we return the resulting stream
return outgoing;
}
我希望这能有所帮助!