在-React-中用事件驱动进行状态管理

33次阅读

共计 6670 个字符,预计需要花费 17 分钟才能阅读完成。

作者:Abdulazeez Abdulazeez Adeshina

翻译:疯狂的技术宅

原文:https://blog.logrocket.com/ev…

未经容许严禁转载

自 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 的例子:

import {createStoreon} from 'storeon/react'
// todos module
const todos = store => {store.on(event, callback)
}

export default const store = createStoreon([todos])

模块化

Storeon 中的 store 是模块化的,也就是说,它们是独立定义的,并且没有被绑定到 Hook 或组件。每个状态及其操作方法均在被称为模块的函数中定义。这些模块被传递到 createStoreon() 函数中,而后将其注册为全局 store。

store 有三种办法:

  1. store.get() – 用于检索状态中的以后数据。
  2. store.on(event, callback) – 用于把事件侦听器注册到指定的事件名称。
  3. store.dispatch(event, data) – 用于收回事件,并依据定义的事件要求将可选数据传递进来。

Events

Storeon 是基于事件的状态治理库,状态更改由状态模块中定义的事件收回。Storeon 中有三个内置事件,它们以 @ 结尾。其余事件不带 @ 前缀定义。三个内置事件是:

  1. @init – 在利用加载时触发此事件。它用于设置利用的初始状态,并执行传递给它的回调中的所有内容。
  2. @dispatch – 此事件在每个新动作上触发。这对于调试很有用。
  3. @changed – 当利用状态产生更改时,将触发此事件。

留神 store.on(event,callback) 用于在咱们的模块中增加事件监听器。

演示程序

为了演示在 Storeon 中如何执行应用程序状态操作,咱们将构建一个简略的 notes 程序。还会用 Storeon 的另一个软件包把状态数据保留在 localStorage 中。

假如你具备 JavaScript 和 React 的基本知识。你能够在 https://github.com/Youngestde… 上找到本文中应用的代码。

设置

在深入探讨之前,让咱们先勾画出 Notes 程序所需的我的项目构造和依赖项的装置。从创立我的项目文件夹开始。

mkdir storeon-app && cd storeon-app
mkdir {src,public,src/Components}
touch public/{index.html, style.css} && touch src/{index,store,Components/Notes}.js

接下来,初始化目录并装置所需的依赖项。

npm init -y
npm i react react-dom react-scripts storeon @storeon/localstorage uuidv4

接下来就是在 index.js 文件中编写父组件了。

index.js

这个文件负责渲染咱们的笔记组件。首先导入所需的包。

import React from 'react'
import {render} from 'react-dom';

function App() {
  return (
    <>
      Hello!
    </>
  );
}
const root = document.getElementById('root');
render(<App />, root);

接下来通过在 store.js 中编写用于状态的初始化和操作的代码来构建 store。

store.js

此文件负责解决利用中的状态和后续状态治理操作。咱们必须创立一个模块来存储状态以及反对事件,以解决操作变更。

首先,从 Storeon 导入 createStoreon 办法和惟一随机 ID 生成器 UUID。

createStoreon 办法负责将咱们的 状态 注册到全局 store。

import {createStoreon} from 'storeon';
import {v4 as uuidv4} from 'uuid'
import {persistState} from '@storeon/localstorage';

let note = store => {}

咱们将状态存储在数组变量 notes 中,该变量蕴含以下格局的正文:

{
  id: 'note id',
  item: 'note item'
},

接下来,咱们将用两个正文(在首次启动程序时会显示)来初始化状态,从而首先填充正文模块。而后,定义状态事件。

let note = store => {store.on('@init', () => ({
    notes: [{ 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.' },
      {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.' },
    ]
  });
  store.on('addNote', ({ notes}, note) => {
    return {notes: [...notes, { id: uuidv4(), item: note }],
    }
  });
  store.on('deleteNote', ({ notes}, id) => ({notes: notes.filter(note => note.id !== id),
  });
}

在下面的代码中,咱们定义了状态,并用两个简短的正文填充了状态,并定义了两个事件和一个从 dispatch(event, data) 函数收回事件后将会执行的回调函数。

addNote 事件中,咱们返回增加了新 note 的更新后的状态对象,在 deleteNote 事件中把 ID 传递给调度办法的 note 过滤掉。

最初,把模块调配给可导出变量 store,将其注册为全局 store,以便稍后将其导入到上下文 provider 中,并将状态存储在 localStorage 中。

const store = createStoreon([
  notes,
  // Store state in localStorage
  persistState(['notes']),
]);
export default store;

接下来,在 Notes.js 中编写 Notes 利用组件。

Notes.js

此文件蕴含 Notes 程序的组件。咱们将从导入依赖项开始。

import React from 'react';
import {useStoreon} from 'storeon/react';

接下来,编写组件。

const Notes = () => {const { dispatch, notes} = useStoreon('notes');
  const [value, setValue] = React.useState(''); 
}

在下面的代码的第二行中,useStoreon() hook 的返回值设置为可毁坏的对象。useStoreon() hook 应用模块名称作为其参数,并返回状态和调度办法以收回事件。

接下来定义在组件中收回状态定义事件的办法。

const Notes = () => {
...
  const deleteNote = id => {dispatch('deleteNote', id)
  };
  const submit = () => {dispatch('addNote', value);
    setValue('');
  };
  const handleInput = e => {setValue(e.target.value);
  };
}

Let’s review the three methods we defined the above:
让咱们回顾一下下面定义的三种办法:

  1. deleteNote(id) – 此办法在触发时调度 deleteNote 事件。
  2. submit() – 该办法通过传递输出状态的值来调度 addNote 事件,该状态在 Notes 组件中本地定义。
  3. handleInput() – 此办法将本地状态的值设置为用户输出。

Next, we’ll build the main interface of our app and export it.
接下来,咱们将构建应用程序的主界面并将其导出。

const Notes = () => {
  ...
  return (
    <section>
      <header>Quick Notes</header>

      <div className='addNote'>
        <textarea onChange={handleInput} value={value} />
        <button onClick={() => submit()}> Add A Note </button>
      </div>

      <ul>
        {notes.map(note => (<li key={note.id}>
            <div className='todo'>
              <p>{note.item}</p>
              <button onClick={() => deleteNote(note.id)}>Delete note</button>
            </div>
          </li>
        ))}
      </ul>
    </section>
  );
}

这样就形成了咱们的 Notes 组件。接下来为咱们的利用和 index.html 文件编写样式表。

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="style.css">
    <title>Storeon Todo App</title>
</head>

<body>
    <div id="root"></div>
</body>

</html>

接下来,填充咱们的 style.css 文件。

style.css

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

section {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  width: 300px;
  margin: auto;
}

header {
  text-align: center;
  font-size: 24px;
  line-height: 40px;
}

ul {display: block;}

.todo {
  display: block;
  margin: 12px 0;
  width: 300px;
  padding: 16px;
  box-shadow: 0 8px 12px 0 rgba(0, 0, 0, 0.3);
  transition: 0.2s;
  word-break: break-word;
}

li {
  list-style-type: none;
  display: block;
}

textarea {
  border: 1px double;
  box-shadow: 1px 1px 1px #999;
  height: 100px;
  margin: 12px 0;
  width: 100%;
  padding: 5px 10px;
}

button {
  margin: 8px 0;
  border-radius: 5px;
  padding: 10px 25px;
}

.box:hover {box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
}

运行

当初咱们曾经胜利编写了组件和样式表,然而还没有更新 index.js 中的父组件来渲染 Notes 组件。接下来让咱们渲染 Notes 组件。

index.js

要拜访咱们的全局 store,必须导入 store 和 Storeon store 上下文组件。咱们还将导入 notes 组件来进行渲染。

用以下代码替换组件的内容:

import React from 'react';
import {render} from 'react-dom';
import {StoreContext} from 'storeon/react';
import Notes from './Components/Notes';
import store from '../src/store';

function App() {
  return (
    <>
      <StoreContext.Provider value={store}>
        <Notes />
      </StoreContext.Provider>
    </>
  );
}

const root = document.getElementById('root');
render(<App />, root);

在第 8-10 行,调用 store 上下文提供程序组件,并将 notes 组件作为使用者传递。store 上下文提供程序组件将全局 store 作为其上下文值。

接下来把 package.json 文件中的脚本局部编辑为以下内容:

"scripts": {"start": "react-scripts start",}

而后运行咱们的程序:

npm run start

让咱们持续增加和删除正文:

Storeon devtools

Storeon 与 Redux 有着类似的属性,能够在 Redux DevTools 中可视化和监督状态的更改。为了可视化 Storeon 程序中的状态,咱们将导入 devtools 包,并将其作为参数增加到咱们 store.js 文件的 createStoreon() 办法中。

...
import {storeonDevtools} from 'storeon/devtools';
...
const store = createStoreon([
  ...,
  process.env.NODE_ENV !== 'production' && storeonDevtools,
]);

这是用 Redux DevTools 可视化状态变动的演示:

论断

Storeon 是一个十分有用的状态治理库,它用事件驱动和 Redux 改编的模块化款式来治理状态。你能够在 https://github.com/Youngestde… 上找到本文中的代码。


本文首发微信公众号:前端先锋

欢送扫描二维码关注公众号,每天都给你推送陈腐的前端技术文章

欢送持续浏览本专栏其它高赞文章:

  • 深刻了解 Shadow DOM v1
  • 一步步教你用 WebVR 实现虚拟现实游戏
  • 13 个帮你进步开发效率的古代 CSS 框架
  • 疾速上手 BootstrapVue
  • JavaScript 引擎是如何工作的?从调用栈到 Promise 你须要晓得的所有
  • WebSocket 实战:在 Node 和 React 之间进行实时通信
  • 对于 Git 的 20 个面试题
  • 深刻解析 Node.js 的 console.log
  • Node.js 到底是什么?
  • 30 分钟用 Node.js 构建一个 API 服务器
  • Javascript 的对象拷贝
  • 程序员 30 岁前月薪达不到 30K,该何去何从
  • 14 个最好的 JavaScript 数据可视化库
  • 8 个给前端的顶级 VS Code 扩大插件
  • Node.js 多线程齐全指南
  • 把 HTML 转成 PDF 的 4 个计划及实现

  • 更多文章 …

正文完
 0