惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Tailwind CSS Blog
博客园 - Franky
博客园 - 司徒正美
Stack Overflow Blog
Stack Overflow Blog
GbyAI
GbyAI
Y
Y Combinator Blog
Microsoft Azure Blog
Microsoft Azure Blog
Blog — PlanetScale
Blog — PlanetScale
博客园 - 叶小钗
罗磊的独立博客
The GitHub Blog
The GitHub Blog
H
Help Net Security
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Engineering at Meta
Engineering at Meta
Martin Fowler
Martin Fowler
Spread Privacy
Spread Privacy
Google DeepMind News
Google DeepMind News
AWS News Blog
AWS News Blog
N
Netflix TechBlog - Medium
T
The Exploit Database - CXSecurity.com
云风的 BLOG
云风的 BLOG
小众软件
小众软件
aimingoo的专栏
aimingoo的专栏
Cyberwarzone
Cyberwarzone
T
Threatpost
T
Threat Research - Cisco Blogs
Recent Announcements
Recent Announcements
T
Tor Project blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Last Week in AI
Last Week in AI
L
Lohrmann on Cybersecurity
量子位
V
V2EX
V
Vulnerabilities – Threatpost
L
LINUX DO - 热门话题
www.infosecurity-magazine.com
www.infosecurity-magazine.com
P
Proofpoint News Feed
I
Intezer
Schneier on Security
Schneier on Security
雷峰网
雷峰网
B
Blog RSS Feed
Jina AI
Jina AI
爱范儿
爱范儿
Attack and Defense Labs
Attack and Defense Labs
Google DeepMind News
Google DeepMind News
M
MIT News - Artificial intelligence
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Palo Alto Networks Blog
美团技术团队
博客园 - 【当耐特】

博客园 - 小笨笨

C# 面试题整理 《ASP.NET Core 6 框架揭秘》第五章读书笔记 - 配置选项(上) 《ASP.NET Core 6 框架揭秘》第四章读书笔记 - 文件系统 Entity Framework Core 笔记 - 入门 《ASP.NET Core 6 框架揭秘》第三章读书笔记 - 依赖注入(下) React 学习笔记之二 - React 详解 《Kafka 权威指南》之二 - 安装 Kafka 《Kafka 权威指南》读书笔记之一 - 初识Kafka React 学习笔记之一 - ES6 基础 微服务实战读书笔记-第一章 缠论 jQuery 实战读书笔记之第六章:事件本质 jQuery 实战读书笔记之第五章:使用 jQuery 操作页面 jQuery 实战读书笔记之第四章:使用特性、属性和数据 jQuery 实战读书笔记之第三章:操作 jQuery 集合 jQuery 实战读书笔记之第二章:选择元素 TCP/IP详解读书笔记:ARP-地址解析协议 TCP/IP详解读书笔记:链路层 TCP/IP详解读书笔记:概述
React 学习笔记之三 - 基于 Redux 状态管理
小笨笨 · 2022-11-29 · via 博客园 - 小笨笨

组件嵌套多层时,可能需要把父级的状态一层一层向下传递,这样在管理和使用上极其不便。

Redux 是 JS 的状态容器,提供可预测化的状态管理。在 React 中使用 Redux,可以把所有的 state 集中到组件顶部,能灵活地将所有 state 分发给所有的组件。

3.1 Redux 使用

Redux 本身不依赖于任何库,可以与任何 UI 层框架搭配使用,大小也只有 2KB。

核心概念

  1)store:一个数据容器,用来管理和保存项目的 state,整个应用只能有一个 store。

  2)state:一个对象,在 state 中存储相应的数据,需要时通过 store 提供的方法获取。

  3)action:一个通知命令,视图层发起的一个操作,对 state 进行修改。

3.1.1 action、createStore 和 reducer 函数

action 本质上是一个 JS 普通对象,必须包含一个字符串类型的 type 属性,代表要对 state 做何种操作。最终 action 通过 store 传入 reducer 函数,完成对 state的修改。

Redux Toolkit 是官方推荐的用于编写 Redux 逻辑的方式,它包含了 Redux Core,还包含了对创建 Redux 应用非常必要的包和功能。

安装 Redux Core:npm install redux

安装 Redux Toolkit:npm install @reduxjs/toolkit

先看 Redux 中的核心方法 createStore,用于创建项目中的 store。

 1      /**
 2          * This is a reducer - a function that takes a current state value and an
 3          * action object describing "what happened", and returns a new state value.
 4          * A reducer's function signature is: (state, action) => newState
 5          *
 6          * The Redux state should contain only plain JS objects, arrays, and primitives.
 7          * The root state value is usually an object. It's important that you should
 8          * not mutate the state object, but return a new object if the state changes.
 9          *
10          * You can use any conditional logic you want in a reducer. In this example,
11          * we use a switch statement, but it's not required.
12          */
13         function counterReducer(state = { value: 0 }, action) {
14             switch (action.type) {
15                 case 'counter/incremented':
16                 return { value: state.value + 1 }
17                 case 'counter/decremented':
18                 return { value: state.value - 1 }
19                 default:
20                 return state
21             }
22         }
23 
24         // Create a Redux store holding the state of your app.
25         // Its API is { subscribe, dispatch, getState }.
26         let store = createStore(counterReducer)

createStore 创建 store 时需要传入 reducer 函数。reducer 是一个函数,它接受当前状态值和描述“发生了什么”的操作对象,并返回一个新的状态值。

在 Redux 中,所有的数据都会保存在同一个 state 对象中。

3.1.2 store

store 的三个常用方法。

  1)getState:用于获取 state。

  2)dispatch(action):发起一个 action。

  3)subscribe(listener):注册一个监听器监听 state 发生的变化。返回一个注销监听器的方法,用于取消监听器。

Redux 基本流程:基于 reducer 创建 store,从 store 中获取 state 传递给视图,当视图被操作时,通过 dispatch 发起一个 action,store 接到 action 后,把 state 和 action 传递给 reducer,reducer 更新 state 并把新的 state 传给视图进行更新。

下面是纯 Redux 的测试代码:

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <title>React Demo</title>
 5         <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
 6         <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
 7         <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.2.0/redux.min.js" crossorigin></script> 
 8     </head>
 9     <body>
10         <div>
11             <p>
12                 <span id="colorEL">Watch my color.</span>    
13                 <button id="red">RED</button>
14                 <button id="green">GREEN</button>
15                 <button id="toggle">TOGGLE</button>            
16             </p>            
17         </div>
18         <script>
19             var initialState = { color: 'red' };
20 
21             // Reducer
22             function colorReducer(state, action){
23                 if(typeof state == 'undefined'){
24                     console.log('return initialState');
25                     return initialState;
26                 }
27 
28                 switch(action.type){
29                     case 'RED':
30                         return { color: 'red' };
31                     case 'GREEN':
32                         return { color: 'green' };
33                     case 'TOGGLE':
34                         return state.color == 'red' ? { color: 'green' } : { color: 'red' };
35                     default:
36                         return state;
37                 }
38             }
39 
40             // create store by the reducer
41             var myStore = Redux.createStore(colorReducer);
42             var colorEL = document.getElementById('colorEL');
43 
44             function render(){
45                 colorEL.style.color = myStore.getState().color;
46             }
47 
48             render();
49 
50             myStore.subscribe(render);
51 
52             document.getElementById('red').addEventListener('click', function(){
53                 myStore.dispatch({ type: 'RED' });
54             });
55 
56             document.getElementById('green').addEventListener('click', function(){
57                 myStore.dispatch({ type: 'GREEN' });
58             });
59 
60             document.getElementById('toggle').addEventListener('click', function(){
61                 myStore.dispatch({ type: 'TOGGLE' });
62             });
63         </script>  
64     </body>
65 </html>

3.2 React-Redux

在 React 中直接使用 Redux 特别麻烦,需要一层一层传递 store。

Redux 官方提供了一个 React 绑定库 - React-Redux。

3.2.1 安装与配置

命令:npm install react-redux,需要注意的是,React-Redux 是 Redux 的官方针对 React 开发的扩展库,默认没有在 React 项目中安装,需要手动来安装。React-Redux 是依赖于redux,所以 Redux 也 必须安装。

安装了 React-Redux 之后,就可以把数据和视图进行分离。

  1)第一步,创建 store。

  2)通过 React-Redux 把 store 关联到项目中。

    React-Redux 提供了组件 Provider,它的作用是向后代子孙传递信息。Provider 应该在整个项目的最外层。

3.2.2 connect

React-Redux 提供了 connect 方法用于接收 Provider 传递下来的 store 中的 state 和 dispatch。

下面是一个使用了 connect 的例子。

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <title>React Demo</title>
 5         <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
 6         <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
 7         <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
 8         <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
 9         <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.2.0/redux.min.js" crossorigin></script>
10         <script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/8.0.5/react-redux.min.js" crossorigin></script>
11         <script src="https://unpkg.com/babel-standalone@6/babel.min.js" crossorigin></script>     
12     </head>
13     <body>
14         <div id="root"></div>
15         <script type="text/babel">
16             // Reducer
17             function countFn(state = {
18                 count: 1
19             }, action){
20                 switch(action.type){
21                     case "COUNT_PLUS":
22                         return { count: state.count + 1};
23                     case "COUNT_REDUCE":
24                         return { count: state.count - 1};
25                 }
26 
27                 return state;
28             }
29 
30             // create store by the reducer
31             let store = Redux.createStore(countFn);
32 
33             class App extends React.Component{
34                 render(){
35                     let {count, dispatch} = this.props;
36 
37                     return (
38                         <div>
39                             <button onClick={() => {
40                                 dispatch({type: "COUNT_REDUCE"});
41                             }}>-</button>
42                             <span>{count}</span>
43                             <button onClick={() => {
44                                 dispatch({type: "COUNT_PLUS"});
45                             }}>+</button>
46                         </div>
47                     );
48                 }
49             }
50 
51             App = ReactRedux.connect(state => state)(App);
52 
53             ReactDOM.createRoot(document.querySelector('#root'))
54                 .render(<ReactRedux.Provider store={store}>
55                             <App />
56                         </ReactRedux.Provider>);
57         </script>  
58     </body>
59 </html>

3.2.3 Hooks

React-Redux 7.X 新增了 Hooks。

  1)const state = useSelector(state => state)

  useSelector 接收一个回调函数,这个函数会被调用,并且 store 中的 state 会被传递给这个函数,返回值是想要的数据,必须有返回值。

  2)const dispatch = useDispatch()

  返回值为 Redux 的 dispatch 方法。

  3) const store = useStore()

  返回 Redux 的 store。

3.4 reducer 拆分与合并

combineReducers(rootReducer)。

3.5 redux-thunk 中间件

dispatch 一个 action 之后,到达 reducer 之前,进行一些额外的操作,就需要用到 middleware。你可以利用 Redux middleware 来进行日志记录、创建崩溃报告、调用异步接口或者路由等等。
换言之,中间件都是对 store.dispatch() 的增强。

redux-thunk 主要用于解决项目中的异步请求。

  1)安装:npm install redux-thunk。

  2)在创建 store 时,引入中间件。Redux 中提供了 applyMiddleware(...middlewares)方法,把方法的返回值传递给 createStore。

  3)添加完成后可以利用 thunk 做中间处理。使用了 thunk 之后,dispatch 可以接收两种不同类型的参数。参数类型是对象时,不会经过中间件处理而是直接把 action 发送到 reducer。参数类型是函数时,会把 dispatch 和 getState 作为参数传递给该函数,在函数中进行中间处理,处理之后调用 dispatch 更新 state。