现在有很多人在谈论redux城的最新成员,redux-saga/redux-saga。它使用生成器函数来监听/分派动作。

在我把我的脑袋绕在它周围之前,我想知道使用redux-saga的优点/缺点,而不是下面的方法,我使用redux-thunk与async/await。

组件可能是这样的,像往常一样分派动作。

import { login } from 'redux/auth';

class LoginForm extends Component {

  onClick(e) {
    e.preventDefault();
    const { user, pass } = this.refs;
    this.props.dispatch(login(user.value, pass.value));
  }

  render() {
    return (<div>
        <input type="text" ref="user" />
        <input type="password" ref="pass" />
        <button onClick={::this.onClick}>Sign In</button>
    </div>);
  } 
}

export default connect((state) => ({}))(LoginForm);

然后我的动作看起来像这样:

// auth.js

import request from 'axios';
import { loadUserData } from './user';

// define constants
// define initial state
// export default reducer

export const login = (user, pass) => async (dispatch) => {
    try {
        dispatch({ type: LOGIN_REQUEST });
        let { data } = await request.post('/login', { user, pass });
        await dispatch(loadUserData(data.uid));
        dispatch({ type: LOGIN_SUCCESS, data });
    } catch(error) {
        dispatch({ type: LOGIN_ERROR, error });
    }
}

// more actions...

// user.js

import request from 'axios';

// define constants
// define initial state
// export default reducer

export const loadUserData = (uid) => async (dispatch) => {
    try {
        dispatch({ type: USERDATA_REQUEST });
        let { data } = await request.get(`/users/${uid}`);
        dispatch({ type: USERDATA_SUCCESS, data });
    } catch(error) {
        dispatch({ type: USERDATA_ERROR, error });
    }
}

// more actions...

当前回答

为了给这个答案一些上下文:嗨,我是Redux维护者。

我们最近在Redux文档中添加了一个新的Side Effects methods页面,它将提供关于所有这些内容的许多信息,但我将尝试在这里写一些简短的内容,因为这个问题得到了大量的曝光。

在2022年,我们将监听器中间件添加到官方Redux工具包中,用于“响应式Redux逻辑”。它可以做sagas可以做的大部分事情(例外是通道),而不需要生成器语法和更好的TypeScript支持。 但这并不意味着你应该用侦听器中间件来编写所有的东西——我们建议在可能的情况下总是先使用thks,在thks不能做你想做的事情时再使用侦听器中间件。

一般来说,我们在2023年的立场是,只有当你有其他中间件无法满足的特定需求时,你才应该使用saga。(本质上:如果你需要频道。)

我们的建议是:

数据抓取

使用RTK Query作为数据获取和缓存的默认方法 如果RTKQ不完全适合,使用createAsyncThunk 只有在其他方法都没用的情况下,才会求助于手写的感谢信 不要使用saga或可观察对象来获取数据!

对动作/状态变化做出反应,异步工作流

使用RTK监听器作为默认响应存储更新和编写长时间运行的异步工作流 只有当监听器不能很好地解决你的用例时,才使用saga / observable

带有状态访问的逻辑

对于复杂的同步和适度的异步逻辑,包括对getState的访问和调度多个操作,可以使用坦克

其他回答

一个小提示。生成器是可取消的,async/await - not。 举个例子,选什么并没有什么意义。 但对于更复杂的流,有时没有比使用生成器更好的解决方案了。

所以,另一个想法可能是使用带有还原坦克的发电机,但对我来说,这就像试图发明一辆有方轮子的自行车。

当然,生成器更容易测试。

这是一个结合了redux-saga和redux-thunk最好的部分(优点)的项目:你可以处理所有的副作用,同时通过调度相应的行动获得承诺: https://github.com/diegohaz/redux-saga-thunk

class MyComponent extends React.Component {
  componentWillMount() {
    // `doSomething` dispatches an action which is handled by some saga
    this.props.doSomething().then((detail) => {
      console.log('Yaay!', detail)
    }).catch((error) => {
      console.log('Oops!', error)
    })
  }
}

除了图书馆作者相当彻底的回答之外,我将添加我在生产系统中使用saga的经验。

优点(使用saga):

Testability. It's very easy to test sagas as call() returns a pure object. Testing thunks normally requires you to include a mockStore inside your test. redux-saga comes with lots of useful helper functions about tasks. It seems to me that the concept of saga is to create some kind of background worker/thread for your app, which act as a missing piece in react redux architecture(actionCreators and reducers must be pure functions.) Which leads to next point. Sagas offer independent place to handle all side effects. It is usually easier to modify and manage than thunk actions in my experience.

Con:

发电机的语法。 有很多概念要学。 API的稳定性。redux-saga似乎还在添加新功能(比如Channels?),社区也没有那么大。如果库有一天进行了不向后兼容的更新,就会有问题。

为了给这个答案一些上下文:嗨,我是Redux维护者。

我们最近在Redux文档中添加了一个新的Side Effects methods页面,它将提供关于所有这些内容的许多信息,但我将尝试在这里写一些简短的内容,因为这个问题得到了大量的曝光。

在2022年,我们将监听器中间件添加到官方Redux工具包中,用于“响应式Redux逻辑”。它可以做sagas可以做的大部分事情(例外是通道),而不需要生成器语法和更好的TypeScript支持。 但这并不意味着你应该用侦听器中间件来编写所有的东西——我们建议在可能的情况下总是先使用thks,在thks不能做你想做的事情时再使用侦听器中间件。

一般来说,我们在2023年的立场是,只有当你有其他中间件无法满足的特定需求时,你才应该使用saga。(本质上:如果你需要频道。)

我们的建议是:

数据抓取

使用RTK Query作为数据获取和缓存的默认方法 如果RTKQ不完全适合,使用createAsyncThunk 只有在其他方法都没用的情况下,才会求助于手写的感谢信 不要使用saga或可观察对象来获取数据!

对动作/状态变化做出反应,异步工作流

使用RTK监听器作为默认响应存储更新和编写长时间运行的异步工作流 只有当监听器不能很好地解决你的用例时,才使用saga / observable

带有状态访问的逻辑

对于复杂的同步和适度的异步逻辑,包括对getState的访问和调度多个操作,可以使用坦克

在我回顾了一些不同的大型React/Redux项目的经验后,Sagas为开发人员提供了一种更结构化的代码编写方式,更容易测试,也更不易出错。

是的,刚开始这有点奇怪,但大多数开发者在一天之内就足够理解它了。我总是告诉人们不要担心yield一开始会做什么,一旦你写了几个测试,它就会来找你。

我曾经见过一些项目,在这些项目中,坦克被当作MVC模式的控制器来处理,这很快就变成了一个不可维护的混乱。

我的建议是,当你需要A触发B类型的与单个事件相关的东西时使用saga。对于任何可能跨越许多操作的东西,我发现编写自定义中间件并使用FSA操作的元属性来触发它更简单。