前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >从零开始的 Redux

从零开始的 Redux

作者头像
Innei
发布2021-12-28 11:31:31
3620
发布2021-12-28 11:31:31
举报
文章被收录于专栏:静之森

Redux 是什么

Redux 是 JavaScript 状态容器,提供可预测化的状态管理。 目前一般与 React 配合使用。React 提供了 React-redux 库,两者能轻松结合起来。

开始之前需要知道的东西

为什么需要状态管理?

  • 多次向下传递 props 过于繁琐
  • 同一个 api 可能在不同情况下请求多次

如果你有 Vuex 的开发经验,那么上手起来会很快。

简单上手

在 Redux 中,状态 (state) 是通过 action 改变的,而 action 其实调用了 reducer 方法。一个 action 能告诉 reducer,下一步做出的动作 (type) 是什么,应该如何去改变数据。

对比 Vuex,一般在 Vuex 中我们通过 action 提交 (commit) 一个 state 的更改。而在 Redux 中是 action 调用了 reducer。

首先我们新建一个 store。

js

代码语言:javascript
复制
1// src/store/index.js
2import { createStore } from 'redux';
3
4import reducer from './reducers';
5export default createStore(reducer);

COPY

新建 store 需要传入一个 reducer。在这里我们来写一个小范例,state 记录一个数据,通过 action 改变他的大小。

js

代码语言:javascript
复制
1import T from '../actions/types';
2// import { add } from '../actions';
3import { combineReducers } from 'redux';
4
5const initState = {
6  num: 1
7};
8
9const change = (state = initState, action) => {
10  const { type, num } = action;
11  console.log(num);
12
13  switch (type) {
14    case T.ADD:
15      return {
16        num: ++state.num
17      };
18    case T.REDUCE:
19      return {
20        num: --state.num
21      };
22    default:
23      return state;
24  }
25};
26
27export default combineReducers({
28  change
29});

COPY

前面提到 action 调用 reducer,所以我们需要一个 action。

js

代码语言:javascript
复制
1import T from './types';
2
3export function add(num) {
4  return {
5    type: T.ADD,
6    num
7  };
8}
9export function reduce(num) {
10  return {
11    type: T.REDUCE,
12    num
13  };
14}

COPY

js

代码语言:javascript
复制
1// store/actions/types.js
2export const types = Object.freeze({
3  ADD: 'ADD',
4  REDUCE: 'REDUCE'
5});
6
7export default types;

COPY

一个 action 由一个 type 和一个 payload 组成,type 是告诉 reducer 应采取哪种更新方式。

我们再来看一下 reducer 由什么组成。

js

代码语言:javascript
复制
1// src/store/reducers/index.js
2import T from '../actions/types'; // 一般可以把 actionTypes 统一记录到一个文件中
3import { combineReducers } from 'redux';
4
5const initState = {   // 原始 states
6  num: 1
7};
8
9// ADD 变量名作为 getStates 中的 key
10const change = (state = initState, action) => {
11  // state 默认不存在所以需要制定默认值,也就是初始化,初始化之后每次调用都会传入未被更新的 state
12  // action 中记录了我们制定的 type, payload, 这里是 num
13  const { type, num } = action;
14
15  switch (type) {
16      // 判断类型,改变数据。应返回一个新的 state。注意:必须是新对象而不是一个引用
17
18    case T.ADD:
19      return {
20        num: state.num + num
21      };
22		case T.REDUCE:
23      return {
24        num: --state.num
25      };
26    default:
27      // 不匹配的 action 类型,直接返回。
28      // 一个 action 会被多个 reducer 接收,注意类型的监听。
29      return state;
30  }
31};
32
33// 使用 combineReducers 连接多个 reducers,虽然这里就一个
34export default combineReducers({
35  change
36});

COPY

至此一个存储数字,并能通过 action 改变他的大小的 store 就写好了。然后我们在 react 中使用它。

js

代码语言:javascript
复制
1// app.js
2
3import store from './store';
4ReactDOM.render(
5    <App {...store} />,
6  document.getElementById('root')
7);

COPY

将 store 实例挂载到根组件,下一层组件能通过 props 接收。

https://cdn.jsdelivr.net/gh/innei/img-bed@master/20200108160130.png
https://cdn.jsdelivr.net/gh/innei/img-bed@master/20200108160130.png

通过 getState 方法我们可以拿到 store 中存储的值,比如我想拿到 change reducer 中的 state。

console.log(this.props.getState().change);

https://cdn.jsdelivr.net/gh/innei/img-bed@master/20200108160346.png
https://cdn.jsdelivr.net/gh/innei/img-bed@master/20200108160346.png

也可以通过 dispatch 方法修改 state 的值。this.props.dispatch(add(1))

到这里 redux 基本算是入门了,接下来是和 React 绑定。不知道有没有注意到开始从根组件传参只能传一层,违背了 store 随时随地使用的原理。这时候 react-redux 登场了。

react-redux 提供一个 Provider 高阶组件,传入一个 store,接下来在下层的所有子组件中用只要使用 connect 方法就可获取到 store。

js

代码语言:javascript
复制
1import store from './store';
2import { Provider } from 'react-redux';
3ReactDOM.render(
4  <Provider store={store}>
5    <App />
6  </Provider>,
7  document.getElementById('root')
8);

COPY

在子组件中不再导出一个默认的 Component,而是导出一个 connect Component。

js

代码语言:javascript
复制
1import React, { Component } from 'react';
2import { connect } from 'react-redux';
3import { add, reduce } from '../store/actions';
4import styles from './style.module.css';
5class Demo extends Component {
6  render() {
7    console.log(this.props);
8
9    return (
10      <div className={styles['wrap']}>
11        <button onClick={() => this.props.add(1)}>+</button>
12        <span style={{ color: '#fff' }}>{this.props.num}</span>
13        <button onClick={() => this.props.reduce(1)}>-</button>
14      </div>
15    );
16  }
17}
18const mapStateToProps = state => {
19  return {
20    num: state.change.num
21  };
22};
23const mapDispatchToProps = dispatch => {
24  return {
25    add: num => dispatch(add(num)),
26    reduce: num => dispatch(reduce(num))
27  };
28};
29
30export default connect(mapStateToProps, mapDispatchToProps)(Demo);

COPY

mapStateToProps 仔细看是不是和 mapGetter 有点像。mapStateToProps 接收一个 state,返回一个对象,这个对象会直接被挂载到 props 上。

mapDispatchToProps 又如同 mapActions,他返回一个对象,这个对象也会直接被挂载到 props 上。这个对象中的函数返回一个函数,可以接收参数,并调用 dispatch 改变 state。

https://cdn.jsdelivr.net/gh/innei/img-bed@master/20200108161854.png
https://cdn.jsdelivr.net/gh/innei/img-bed@master/20200108161854.png
https://cdn.jsdelivr.net/gh/innei/img-bed@master/2020-01-08%2016.23.14.gif
https://cdn.jsdelivr.net/gh/innei/img-bed@master/2020-01-08%2016.23.14.gif
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-01-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Redux 是什么
  • 开始之前需要知道的东西
  • 简单上手
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档