Redux-Saga 实例教程:构建 Reddit 的 SPA 应用

Redux-Saga 是 Redux 的一个中间件,它用于处理异步操作和副作用。它类似于 Redux-Thunk,但提供了更多的功能和控制,例如取消异步操作,处理复杂的任务和操作序列等。在本文中,我们将使用 Redux-Saga 构建一个单页应用程序,该应用程序使用 Reddit API 获取新闻和帖子列表,并允许用户通过搜索功能查找这些信息。

什么是 Reddit?

Reddit 是一个全球知名的社交新闻聚合网站,用户可以发布和讨论各种内容,如新闻、图片、视频、游戏、科技、体育等等。Reddit 的用户可以在所述社区内发布内容,通常是以纯文本形式发布,其他用户可在该帖子下面进行讨论和回复。 Reddit 还提供了“投票”功能,可以在投票中选出流行的帖子,使其更加突出。

准备工作

在开始构建RedditSPA之前,请确保您已经安装了必要的软件:

  • Node.js 和 npm 包管理器
  • Yarn 包管理器

本教程还使用了以下工具和库:

  • React 前端框架
  • Redux 状态管理库
  • Redux-Saga 异步中间件
  • Axios HTTP 客户端库
  • React-Router 前端路由库

您可以使用以下命令安装它们:

我们还需要 Reddit 的开发者 API 密钥。您可以在Reddit 开发者门户注册一个应用程序并获取它。从 Reddit 获取的 API 密钥是机密的,请勿在任何公共代码存储库中包含它。

程序代码已放在 GitHub 上,你可以 clone 到本地执行查看。

实现 Reddit API 接口

为了从 Reddit 的 API 获取信息,我们需要编写一个 API 客户端。使用 Axios 可以轻松地完成 HTTP 请求,而且我们还可以设置请求头和拦截器以处理响应和错误。

我们主要是使用 axios.create() 方法创建API客户端,指定了 Reddit 的基本 URL,{'User-Agent': 'redux-saga'}} 用于 Reddit API 要求一个请求头部分指定用户代理,我们还定义了一个 getPosts 函数,它使用指定的子Reddit,并向 Reddit API 发出 GET 请求以检索新帖子列表。

构建 Redux Store

在我们的应用程序中,我们需要存储 Reddit API 返回的新闻和文章列表。我们将使用 Redux 来管理应用程序状态,创建一个 Redux store。

Actions

我们使用 Redux 定义一些 actions 来控制 store。我们使用它来请求 Reddit API 并将结果存储在 store 中。我们同时定义了一个 setFilter action 以设置当前 Reddit 主题的过滤器值。

我们使用 type 字段为每个 action 定义一个唯一的名字,payload 字段存储有关请求和响应的数据。在上面的代码中,我们定义了 5 个 actions:

  • SELECT_SUBREDDIT:设置当前 Reddit 的主题子版块。
  • INVALIDATE_SUBREDDIT:通知 Redux store 文章已过期,需要重新加载。
  • REQUEST_POSTS:请求 Reddit API 并通知 store。
  • RECEIVE_POSTS:接收 Reddit API 返回的文章并将其存储在 store 中。
  • SET_FILTER:设置当前 Reddit 主题的过滤器值。

我们需要使用 reducer 函数组合上面的actions

Reducers

Redux 应用的 reducer 管理着它的 state(状态)的更新。我们需要定义以下 actions 的状态存储方式以及如何响应 those actions:

Redux Store 由四个 reducer 函数组成:

  • subreddit:纯函数,存储当前 Reddit 的子版块名称。
  • filter:纯函数,存储当前 Reddit 主题的过滤器值。
  • posts:纯函数,存储 Reddit API 返回的新闻和文章列表。
  • postsBySubreddit:纯函数,用来组合上面的 three reducer,并以“子Reddit”为键存储他们的值。

注意以上的reducer函数操作每个状态域的方法,分别是状态key项的名称(如上的 items),不同action可能会改变相同或不同的键的值。

Store

Store 定义了 actions、reducers 和中间件的集合。在我们的应用程序中,它通过存储所有 Reddit 相关的状态信息来帮助我们控制整个应用程序的行为。

其中 rootSaga 是 Redux Saga 应用程序里的核心逻辑部分。

实现 Reddit Saga

我们使用 Redux-Saga 中间件模块来处理异步操作和副作用。Sagas 是一些用于处理副作用(如读取和写入磁盘、发出 HTTP 请求、访问浏览器缓存等)的函数, Saga 将它们的执行与 Redux Store 的状态同步。在本文中,我们将大量使用 Sagas 来管理应用程序中的所有操作。

Reddit Api Saga,处理请求和响应

以下是 Reddit API 请求和响应过程的 Saga 函数。

requests-saga.js

这里我们引入了一些 Redux-Saga 的顶级函数:

  • takeLatest:对于同一个 action 的每个新实例,以非阻止屏幕模式较新的 call fork cancel 效果来选择仅最新的一个发生,并立即取代之前的 saga。
  • call:在 Saga 中调用函数。
  • put:分发一个 Action。
  • getSubreddit / getFilter:从 store 中选择当前 Reddit 主题和过滤器值,以便向 Reddit API 发出正确的请求。
  • fetchPosts:由我们之前实现的我们的Reddit客户端调用Reddit API。

类 Reddit 页面 Saga

在 Reddit API 请求成功后,我们需要将 HTML 格式的结果渲染为页面元素。我们使用 React 组件来处理 UI,并将 Sagas 用于一些类似于组件生命周期函数的操作。下面是约会 Reddit 页面的 Saga 函数。

front-page-saga.js

我们定义了 5 个 Saga 函数:

  • invalidateSubredditSaga:通知 store subreddit 已失效,需要重新请求新的文章。
  • selectSubredditSaga:使用 Reddit API 请求和响应新的文章、更新 store 中的列表。
  • setFilterSaga:使用 Reddit API 请求和响应过滤器,更新 store 中的 filter 状态。
  • shouldFetchPosts:检查 store 是否具有失效状态、未开始拉取状态、已过期状态。 如果是,我们需要重新请求新的文章。
  • fetchPostsIfNeededSaga:该 Saga 函数根据 shouldFetchPosts() 执行是否需要更新 Reddit API,如果需要,则发送 get 请求来获取 Reddit API 新的文章。

以上 5 个 Saga 函数用于监听 Reddit 页面动作,并在页面发生上述动作时调用。

Root Saga:组合所有 Sagas

我们使用根 Saga 将上述所有 Sagas 组合在一起。

我们不需要使用一个 Saga 来处理所有的 action,而是使用多个 Saga 并使用 all() 函数将它们组合在一起。

渲染 Reddit SPA 应用

我们需要定义一个使用 React 的 Reddit App 组件,以便渲染 Reddit 应用。 Reddit App 具有以下功能:

  • Header:应用程序的标题以及 Reddit 的子版块的菜单。
  • Sidebar:显示 Reddit 主题的过滤器。
  • Main:Reddit 的新闻和文章列表。
  • 新闻和文章列表项。

在 Redux 中,我们将 Reddit App 整体作为一个容器组件实现,Redux 将负责管理 Reddit 的状态信息。根据 store 中的数据,AppComponent会从 Reddit.API 获取数据,并将其传递给 Reddit.Content.

App.jsx

组件

下面是 Reddit 应用程序的组件定义。

Header.jsx

Sidebar.jsx

Subreddit.jsx

Filter.jsx

Content.jsx

Article.jsx

到此为止,这个 Reddit 应用程序就完成了。

总结

在示例代码中,我使用了 React、Redux 和 Redux-Saga,还使用了 React-Router 和 Axios 库。这些技术和库对于构建单页应用程序非常有效,我们可以模块化地开发应用程序,拆分组件、代码和功能,使代码易于阅读、维护和扩展。

Redux-Saga 可以协调所有异步操作和副作用,使应用程序非常健壮。 Sagas 的执行也更容易进行测试,因为我们可以一步一步地处理所有副作用。此外,Redux-Saga 对于取消异步操作和处理复杂异步操作非常方便,我们只需设置相应的逻辑即可。

重点在 Saga 代码的接收和处理,比较繁琐,要点需要记清楚。将action提交到store,由reducer进行交互,需要注意的是每个reducer的状态域,注意处理方法。

完整的源码可以参见这里

希望对初学Redux和Sagas的读者有所启发和帮助。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/654f36e97d4982a6eb831d23


纠错
反馈