在React中如何使用Hookstate的状态管理

394 阅读6分钟

开始使用HookState库

React.js是一个成熟的JavaScript库,用于声明性和动态用户界面。React.js将用户界面分解为多个组件。在React.js编程中,状态的概念是至关重要的。

我们需要知道什么是状态,如何有效地维护它,以及如何处理随着应用程序的扩展而增加的复杂性。

在这篇文章中,我们将使用Hookstate库学习React.js中状态管理的基本知识。

前提条件

作为一个前提条件,读者必须具备以下条件。

  • 一个网络浏览器,[如谷歌浏览器]。
  • 一个代码编辑器,如[VS Code]或任何首选IDE。
  • 对[JavaScript]编程语言的了解。
  • [React库]的基础知识。
  • 在你的开发环境上有一个[Node.js]LTS或更高版本。

了解状态管理

简而言之,状态管理是一种模式,我们在现代前端框架的可重复使用的组件中控制数据的通信和共享。

我们的应用程序将数据封装在一个数据结构中,该结构反映了应用程序的逻辑状态,我们可以用它来访问和改变,以便在各种状态之间转换。

应用程序的状态("state")因用户的操作而改变。

一个案例研究可以是一个电子商务应用。例如,一个电子商务网站可以有一些组件,如Button,Cart,Checkout,Login, 以及更多。

当用户向Cart 组件添加物品或执行成功登录时,这些操作将改变我们组件的状态,从而改变整个应用程序的状态。

为什么要使用状态管理库?

在现代的前端应用程序中,我们将UI分解成逻辑上可重用的组件。这些组件往往需要动态数据来共享和传递。

在一个广泛的应用程序中,保持对全局状态的跟踪,同时避免prop 钻空子可能是很困难的。这就是状态管理库的用武之地。

redux不同的是,redux使用reducers、dispatch和action,有时会让人感到困惑,Hookstate库将React中的状态概念提升到一个新的水平。

Hookstate库将声明式ReactuseState 的理念包装成一个全局版本,并以额外的功能对其进行了扩展。

它的一些核心功能包括。

  • 一个插件系统,用于持久化和状态验证来扩展库的功能。
  • Hookstate的标准TypeScript对状态管理的支持。
  • 支持深度嵌套组件中的异步和部分状态更新等等。

应用程序设置

为了搭建一个新的React应用程序的脚手架,我们将使用一个新的前端构建工具,Vite

Vite通过使用Rollup而不是Webpack捆绑预配置的代码,为开发者优化了构建过程。

要用一个基本的React模板启动Vite应用程序,键入以下命令。

npm init vite@latest hookstate-demo -- --template react

接下来,在终端上导航到hookstate-demo 文件夹内,执行npm install 命令。

npm install

接下来,将hookstateuuid 包添加到项目中,如图所示。

npm install --save @hookstate/core uuid

最后,通过运行命令在你的浏览器上启动一个开发服务器。

npm run dev

terminal output

如果我们切换到我们的浏览器并访问URLhttp://localhost:3000/ ,我们应该看到与此类似的东西。

browser demo

创建全局状态

为了创建和管理全局状态,在你的src 目录中添加一个文件夹并命名为states

现在,我们将在states 文件夹下创建一个TaskState.js 文件,包含一个自定义的钩子。我们的函数将调用Hookstate的方法createState([]) 来创建一个新的状态并返回。

导入uuid@hookstate/core 包来创建一个全局状态。

import { createState, useState } from "@hookstate/core";
import {v4 as uuid} from "uuid";

注意:useState 钩子类似于React的内置钩子。当在一个文件中同时访问钩子时,一个别名有助于消除歧义。

在库的导入下面,实例化createState 来创建一个新的状态。

// Initial state - empty array.
const taskState = createState([]);

最后,让我们创建一个自定义钩子,以便在我们的组件中操作状态时重复使用。创建并导出useTaskState 函数。

export function useTaskState() {
}

在函数主体内,添加state 变量来启动来自useState 的状态。

// assign state
const state = useState(taskState);

最后,返回以下函数。

return {
    // addTask method takes the new state and returns a new state using the .set(method)
    addTask(newTask) {
        return state.set((tasks) => [...tasks, { newTask, id: uuid() }]);
    },
    // filter task lists to remove a list item
    removeTask(id) {
        return state.set((tasks) => tasks.filter((task) => task.id !== id));
    },
    // state.get() retieves the Todo list state
    get getTasks() {
        return state.get();
    }
};

让我们简单地剖析一下上面的代码片断。

  • addTask 方法接受一个newTask 参数,代表输入字段中的用户值。最后,该函数从Hookstate返回state.get ,进行突变并添加新的任务。
  • getTasks 方法将通过返回 方法来访问全局存储,其工作原理与React内置的 钩子相同。state. get setState
  • 最后,removeTask 方法访问全局状态并通过ID过滤出任务。

创建AddTodo组件

AddTodo 组件处理用户的输入以呈现一个新的待办事项。在components 文件夹中定义AddTodo.jsx 文件。

我们的组件将重新使用之前的自定义useTaskState ,以访问全局状态。

import { useTaskState } from "../states/TaskState";

在我们的返回语句中,我们添加一个接受新待办事项的输入表单。当用户提交表单时,我们调用onSubmit 事件处理程序来添加新的项目。

创建AddTodo 函数,如下图所示。

const AddTodo = () => {
    const taskState = useTaskState();
    return (
        <div>
            <form
                onSubmit={(e) => {
                e.preventDefault();
                // trim white spaces
                if (!e.target["toDo"].value.trim()) {
                return;
                }
                // add new to-do item
                taskState.addTask(e.target["toDo"].value);
                e.target["toDo"].value = "";
                }}
            >
                {/*An input element and a button */}
                <input name="toDo" />
                <button type="submit">Add Todo</button>
            </form>
        </div>
    );
};

最后,默认导出我们的函数。

export default AddTodo;

TodoList组件

TodoList 组件包含我们的todo 项目。在你的components 文件夹内,添加带有以下代码的TodoList.jsx 文件。

import { useTaskState } from "../states/TaskState";

const ToDoList = () => {
    const taskState = useTaskState();
    const state = taskState.getTasks;
    return (
        <ul>
            {state.length > 0 &&
            state.map((todo) => (
                <li key={todo.id}>
                    <span>{todo.text}</span>
                    {/*Add a delete button*/}
                    <button onClick={() => taskState.removeTask(todo.id)}>
                    Delete
                    </button>
                </li>
            ))}
        </ul>
    );
};

export default ToDoList;

在上面的代码中,我们做了以下工作。

  • 首先,我们从我们的states 文件夹中导入useState 自定义挂钩。
  • const state = taskState.getTasks; 是访问我们状态的变量。
  • 在JSX里面,我们通过循环返回一个带有可用任务列表的<ul> 元素。

App.js组件

我们的主App.js 文件是相当小的。我们需要添加的是ToDoList 组件、AddTodo 组件和useTaskState

import { useTaskState } from "./states/TaskState";
import ToDoList from "./components/ToDoList";
import AddTodo from "./components/AddTodo";

最后,导出App 组件,并将这些组件映射到JSX中。

export default function App() {
    const taskState = useTaskState();
    return (
        <div className="App">
            <h1>TODO APP</h1>
            <AddTodo />
            <ToDoList />
        </div>
    );
}

演示

要运行这个程序,在你的终端上用命令启动一个开发服务器。

npm run dev

如果我们回到我们的浏览器http://localhost:3000/ ,我们最终的应用程序应该与此相似。

todo demo

结论

本教程向你介绍了React中使用Hookstate的状态管理。为了生成全局状态和访问状态存储,我们建立了一个使用该库的API的Todo应用。