概述
正文共:3740 字
预计阅读时间:10 分钟
自 Hook 被引入 React 以来,Context API 与 Hook 库在应用状态管理中被一起使用。但是把 Context API 和 Hooks(许多基于 Hooks 的状态管理库建立在其基础上)组合的用法对于大规模应用来说可能效率不高。
由于必须创建一个自定义的 Hook 才能启用对状态及其方法的访问,然后才能在组件中使用它,所以在实际开发中很繁琐。这违反了 Hook 的真正目的:简单。但是对于较小的应用,Redux 可能会显得太重了。
今天,我们将讨论 Context API 的替代方法:Storeon。Storeon 是一个微型的、事件驱动的 React 状态管理库,其原理类似于 Redux。用 Redux DevTools 可以查看并可视化状态操作。Storeon 内部使用 Context API 来管理状态,并采用事件驱动的方法进行状态操作。
Store
store 是在应用程序状态下存储的数据的集合。它是通过从 Storeon 库导入的 createStoreon()
函数创建的。
createStoreon()
函数接受模块列表,其中每个模块都是一个接受 store
参数并绑定其事件监听器的函数。这是一个store 的例子:
1import { createStoreon } from 'storeon/react'
2// todos module
3const todos = store => {
4 store.on(event, callback)
5}
6
7export default const store = createStoreon([todos])
模块化
Storeon 中的 store 是模块化的,也就是说,它们是独立定义的,并且没有被绑定到 Hook 或组件。每个状态及其操作方法均在被称为模块的函数中定义。这些模块被传递到 createStoreon()
函数中,然后将其注册为全局 store。
store 有三种方法:
store.get()
– 用于检索状态中的当前数据。store.on(event, callback)
– 用于把事件侦听器注册到指定的事件名称。store.dispatch(event, data)
– 用于发出事件,并根据定义的事件要求将可选数据传递进来。
Events
Storeon 是基于事件的状态管理库,状态更改由状态模块中定义的事件发出。Storeon 中有三个内置事件,它们以 @
开头。其他事件不带 @
前缀定义。三个内置事件是:
@init
– 在应用加载时触发此事件。它用于设置应用的初始状态,并执行传递给它的回调中的所有内容。@dispatch
– 此事件在每个新动作上触发。这对于调试很有用。@changed
– 当应用状态发生更改时,将触发此事件。
注意:
store.on(event,callback)
用于在我们的模块中添加事件监听器。
演示程序
为了演示在 Storeon 中如何执行应用程序状态操作,我们将构建一个简单的 notes 程序。还会用 Storeon 的另一个软件包把状态数据保存在 localStorage
中。
假设你具有 JavaScript 和 React 的基本知识。你可以在 https://github.com/Youngestdev/storeon-app 上找到本文中使用的代码。
设置
在深入探讨之前,让我们先勾勒出 Notes 程序所需的项目结构和依赖项的安装。从创建项目文件夹开始。
1mkdir storeon-app && cd storeon-app
2mkdir {src,public,src/Components}
3touch public/{index.html, style.css} && touch src/{index,store,Components/Notes}.js
接下来,初始化目录并安装所需的依赖项。
1npm init -y
2npm i react react-dom react-scripts storeon @storeon/localstorage uuidv4
接下来就是在 index.js
文件中编写父组件了。
`index.js`
这个文件负责渲染我们的笔记组件。首先导入所需的包。
1import React from 'react'
2import { render } from 'react-dom';
3
4function App() {
5 return (
6 <> 7 Hello! 8 > 9 );10}11const root = document.getElementById('root');12render(<App />, root);13
接下来通过在 store.js
中编写用于状态的初始化和操作的代码来构建 store。
`store.js`
此文件负责处理应用中的状态和后续状态管理操作。我们必须创建一个模块来存储状态以及支持事件,以处理操作变更。
首先,从 Storeon 导入 createStoreon
方法和唯一随机ID生成器 UUID。
createStoreon
方法负责将我们的 状态 注册到全局 store 。
1import { createStoreon } from 'storeon';
2import { v4 as uuidv4 } from 'uuid'
3import { persistState } from '@storeon/localstorage';
4
5let note = store => {}
我们将状态存储在数组变量 notes
中,该变量包含以下格式的注释:
1{
2 id: 'note id',
3 item: 'note item'
4},
接下来,我们将用两个注释(在首次启动程序时会显示)来初始化状态,从而首先填充注释模块。然后,定义状态事件。
1let note = store => {
2 store.on('@init', () => ({
3 notes: [
4 { id: uuidv4(), item: 'Storeon is a React state management library and unlike other state management libraries that use Context, it utilizes an event-driven approach like Redux.' },
5 { id: uuidv4(), item: 'This is a really short note. I have begun to study the basic concepts of technical writing and I''m optimistic about becoming one of the best technical writers.' },
6 ]
7 });
8 store.on('addNote', ({ notes }, note) => {
9 return {
10 notes: [...notes, { id: uuidv4(), item: note }],
11 }
12 });
13 store.on('deleteNote', ({ notes }, id) => ({
14 notes: notes.filter(note => note.id !== id),
15 });
16}
在上面的代码中,我们定义了状态,并用两个简短的注释填充了状态,并定义了两个事件和一个从 dispatch(event, data)
函数发出事件后将会执行的回调函数。
在 addNote
事件中,我们返回添加了新 note 的更新后的状态对象,在 deleteNote
事件中把 ID 传递给调度方法的 note 过滤掉。
最后,把模块分配给可导出变量 store ,将其注册为全局 store,以便稍后将其导入到上下文 provider 中,并将状态存储在 localStorage
中。
1const store = createStoreon([
2 notes,
3 // Store state in localStorage
4 persistState(['notes']),
5]);
6export default store;
接下来,在 Notes.js
中编写 Notes 应用组件。
`Notes.js`
此文件包含 Notes 程序的组件。我们将从导入依赖项开始。
1import React from 'react';
2import { useStoreon } from 'storeon/react';
接下来,编写组件。
1const Notes = () => {
2 const { dispatch, notes } = useStoreon('notes');
3 const [ value, setValue ] = React.useState('');
4}
在上面的代码的第二行中,useStoreon()
hook 的返回值设置为可破坏的对象。useStoreon()
hook 使用模块名称作为其参数,并返回状态和调度方法以发出事件。
接下来定义在组件中发出状态定义事件的方法 。
1const Notes = () => {
2...
3 const deleteNote = id => {
4 dispatch('deleteNote', id)
5 };
6 const submit = () => {
7 dispatch('addNote', value);
8 setValue('');
9 };
10 const handleInput = e => {
11 setValue(e.target.value);
12 };
13}
让我们回顾一下上面定义的三种方法:
deleteNote(id)
– 此方法在触发时调度deleteNote
事件。submit()
– 该方法通过传递输入状态的值来调度addNote
事件,该状态在Notes
组件中本地定义。handleInput()
– 此方法将本地状态的值设置为用户输入。
Next, we’ll build the main interface of our app and export it.
接下来,我们将构建应用程序的主界面并将其导出。
1const Notes = () => {
2 ...
3 return (
4 <section> 5 <header>Quick Notesheader> 6 7 <div className='addNote'> 8 <textarea onChange={handleInput} value={value} /> 9 <button onClick={() => submit()}> Add A Note button>10 div>1112 <ul>13 {notes.map(note => (14 <li key={note.id}>15 <div className='todo'>16 <p>{note.item}p>17 <button onClick={() => deleteNote(note.id)}>Delete notebutton>18 div>19 li>20 ))}21 ul>22 section>23 );24}25
这样就构成了我们的Notes
组件。接下来为我们的应用和index.html
文件编写样式表。
`index.html`
1html>
2<html lang="en">
3
4<head>
5 <meta charset="UTF-8">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0">
7 <meta http-equiv="X-UA-Compatible" content="ie=edge">
8 <link rel="stylesheet" href="style.css">
9 <title>Storeon Todo Apptitle>
10head>
11
12<body>
13 <div id="root">div>
14body>
15
16html>
接下来,填充style.css
文件。
`style.css`
1* {
2 box-sizing: border-box;
3 margin: 0;
4 padding: 0;
5}
6
7section {
8 display: flex;
9 justify-content: center;
10 align-items: center;
11 flex-direction: column;
12 width: 300px;
13 margin: auto;
14}
15
16header {
17 text-align: center;
18 font-size: 24px;
19 line-height: 40px;
20}
21
22ul {
23 display: block;
24}
25
26.todo {
27 display: block;
28 margin: 12px 0;
29 width: 300px;
30 padding: 16px;
31 box-shadow: 0 8px 12px 0 rgba(0, 0, 0, 0.3);
32 transition: 0.2s;
33 word-break: break-word;
34}
35
36li {
37 list-style-type: none;
38 display: block;
39}
40
41textarea {
42 border: 1px double;
43 box-shadow: 1px 1px 1px #999;
44 height: 100px;
45 margin: 12px 0;
46 width: 100%;
47 padding: 5px 10px;
48}
49
50button {
51 margin: 8px 0;
52 border-radius: 5px;
53 padding: 10px 25px;
54}
55
56.box:hover {
57 box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
58}
运行
现在我们已经成功编写了组件和样式表,但是还没有更新 index.js
中的父组件来渲染 Notes 组件。接下来让我们渲染 Notes 组件。
`index.js`
要访问我们的全局 store,必须导入 store 和 Storeon store 上下文组件。我们还将导入 notes 组件来进行渲染。
用以下代码替换组件的内容:
1import React from 'react';
2import { render } from 'react-dom';
3import { StoreContext } from 'storeon/react';
4import Notes from './Components/Notes';
5import store from '../src/store';
6
7function App() {
8 return (
9 <>
10 11 12
13 >
14 );
15}
16
17const root = document.getElementById('root');
18render(, root);
在第 8-10 行,调用 store 上下文提供程序组件,并将 notes 组件作为使用者传递。store 上下文提供程序组件将全局 store 作为其上下文值。
接下来把 package.json
文件中的脚本部分编辑为以下内容:
1"scripts": {
2 "start": "react-scripts start",
3}
然后运行我们的程序:
1npm run start
让我们继续添加和删除注释:
Storeon devtools
Storeon 与 Redux 有着相似的属性,可以在 Redux DevTools 中可视化和监视状态的更改。为了可视化 Storeon 程序中的状态,我们将导入 devtools
包,并将其作为参数添加到我们 store.js
文件的 createStoreon()
方法中。
1...
2import { storeonDevtools } from 'storeon/devtools';
3...
4const store = createStoreon([
5 ...,
6 process.env.NODE_ENV !== 'production' && storeonDevtools,
7]);
这是用 Redux DevTools 可视化状态变化的演示:
总结
Storeon 是一个非常有用的状态管理库,它用事件驱动和 Redux 改编的模块化样式来管理状态。你可以在 https://github.com/Youngestdev/storeon-app 上找到本文中的代码。
往期精彩回顾
怎样为你的 Vue.js 单页应用提速
10 个实用的 JavaScript 小技巧
它改变了 JavaScript 的体系结构——Webpack 5 Module Federation
与 JavaScript 模块相关的所有知识点
我们是怎样优化 V8 中的指针压缩的
当一个模块被导入两次时,会发生什么?
ReactJS 与 VueJS:两种流行前端 JS 框架之战
十分钟搞定 TypeScript + webpack 配置
18 个漂亮的 Bootstrap 模板
前端程序员要懂的 UI 设计知识
如果觉得有帮助,请点击“在看”让更多小伙伴知道最后
以上就是个性紫菜为你收集整理的react全局状态管理_在 React 中进行事件驱动的状态管理的全部内容,希望文章能够帮你解决react全局状态管理_在 React 中进行事件驱动的状态管理所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复