网易首页 > 网易号 > 正文 申请入驻

更轻巧的状态管理工具——Hookstate

0
分享至

本文作者为 360 奇舞团前端开发工程师
Hookstate 前言

作为 React 开发人员,管理中型应用程序的状态可能很困难。在开发小型应用程序时,将状态从一个组件传递到另一个组件相对简单。当应用程序的规模发生变化时,就会变得不方便,因为你需要无层级关系组件状态的互相访问支持。

Hookstate是一个完全基于React状态hook的状态管理库。它实施简单、快速、直接且可扩展。不需要模版,它也可以在 Next.js 应用程序中使用。

在本文中,我们将了解如何使用这个库,它是最用户友好的 React 状态管理库之一。

开始使用 Hookstate

在本节中,我们将使用下面的代码块创建一个 React 应用程序:

npx create-react-app react-hookstate
cd react-hookstate

要安装所需的库,请使用以下代码块之一:

npm install --save @hookstate/core @chakra-ui/react @emotion/react @emotion/styled framer-motion axios

或者

yarn add  @hookstate/core @chakra-ui/react @emotion/react @emotion/styled framer-motion axios
Local state

一般来说,当父组件、子组件或仅父组件使用状态时,建议在 React 应用程序中使用本地状态。当多个组件共享一个状态并且应用程序中的每个组件都可以通过这种方式访问该状态时,建议使用全局状态。

为了展示 Hookstate 如何在本地处理状态,我们将利用 useHookstate.

import React from "react";
import { useHookstate } from "@hookstate/core";
import { Box, Button, Flex, Text } from "@chakra-ui/react";

const App = () => {
  const state = useHookstate(0);
  return (
    
      
"flex"       flexDirection= "column"       justifyContent= "center"       alignItems= "center"       maxW= "1440px"       minH= "100vh"       m= "auto"     >        "center" fontWeight= "700" fontSize={{base: "32px", md: "64px"}}>         Counter value: {state.get()}{ " "}                         state.set((p) => p + 1)}  bg= "green" color= "#fff">Increment           state.set((p) => p - 1)}  bg= "red" color= "#fff">Decrement               ); }; export default App;

上面的代码显示了一个计数器应用程序以及我们如何使用 useHookstate,给变量赋值后state,我们将默认值设置为 0 并使用 set 和 get 方法 useHookstate。set 方法用于改变状态,而 get 方法获取状态的值。

Global state

在本节中,我们将了解如何在全局级别管理应用程序中的状态。与上一节一样,这次状态将是全局的,并且可以从应用程序中的任何位置访问。

创建一个新目录src/store/index.js并将以下代码块粘贴到其中:

import { hookstate, useHookstate } from "@hookstate/core";

const initialState = hookstate({
  count: 0,
});

export const useGlobalState = () => {
  const state = useHookstate(initialState);

  return {
    getCount: () => state.count.value,
    increment: () => {
      state.count.set((count) => count + 1);
    },
    decrement: () => {
      state.count.set((count) => count - 1);
    },
  };
};

在前面的代码块中,我们声明了应用程序的 initialState,它有一个包含 的对象 count,其值设置为0。

接下来,我们创建了一个名为 useGlobalState 的自定义 hook,并将参数传递 initialState 给useHookstate。我们在返回块中有三个函数来读取和修改状态。

要全局访问状态,我们必须首先修改App.js组件。

import React from "react";
import { Box, Button, Flex, Text } from "@chakra-ui/react";
import { useGlobalState } from "./store";

const App = () => {
  const state = useGlobalState();

  const increment =()=> {
    state.increment()
  }

  const decrement =()=> {
    state.decrement()
  }

  return (
    
      
"flex"       flexDirection= "column"       justifyContent= "center"       alignItems= "center"       maxW= "1440px"       minH= "100vh"       m= "auto"     >        "center" fontWeight= "700" fontSize={{base: "32px", md: "64px"}}>         Counter value: {state.getCount()}{ " "}                         increment()}  bg= "green" color= "#fff">Increment           decrement()}  bg= "red" color= "#fff">Decrement               ); }; export default App;

我们现在可以通过访问全局状态 useGlobalState,这是从 导入的自定义 hook,我们将其设置为在更新的组件中src/store/index.js调用的变量。我们现在可以全局访问读取和改变状态。stateApp.js

具有 CRUD 功能的全局状态

在本节中,我们将创建一个 CRUD 应用程序。这将展示如何管理应用程序状态的真实示例。

我们将创建一个简单的博客应用程序,第一种方法是创建应用程序的状态和改变它的函数。

将以下代码块添加到 src/store/index 文件中。

import { hookstate, useHookstate } from "@hookstate/core";

const initialState = hookstate({
  blog: [],
});

export const useGlobalState = () => {
  const state = useHookstate(initialState);

  return {
    getCountBlog: () => state.blog.length,
    addBlog: (blog) => {
      state.blog.merge([blog]);
    },
    updateBlog: (id, blog) => {
      state.blog.set((b) =>
        b.map((blogs) => {
          if (blogs.id === id) {
            blogs.content = blog.content;
          }
          return blogs;
        })
      );
    },
    deleteBlog: (id) => {
      state.blog.set((blogs) => blogs.filter((blog) => blog.id !== id));
    },
    fetchBlogs: () => state.blog,
  };
};

我们在上面的代码块中为应用程序创建了五个不同的函数,这些函数可以读取和修改状态。例如 addBlog,该函数使用 merge,它会部分更新应用程序的现有状态。

我们将在 App.js 中创建与src/store/index.

import React, { useEffect, useState } from "react";
import {
  Box,
  Button,
  Card,
  CardBody,
  CardFooter,
  Flex,
  Image,
  Input,
  Stack,
  Text,
} from "@chakra-ui/react";
import { useGlobalState } from "./store";

const App = () => {
  const state = useGlobalState();
  const [data, setData] = useState([]);
  const [content, setContent] = useState("");
  const [edit, setEdit] = useState(false);
  const [updateId, setUpdateId] = useState(0);

  const fetchBlog = () => {
    setData(state.fetchBlogs());
  };

  useEffect(() => {
    fetchBlog();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const addBlog = () => {
    const blog = {
      id: state.getCountBlog() + 1,
      content: content,
    };
    state.addBlog(blog);
    setContent("");
  };

  const updateBlog = (id) => {
    const blog = {
      id,
      content,
    };
    state.updateBlog(id, blog);
    setContent("");
    setUpdateId(0);
    setEdit(false);
  };

  const deleteBlog = (id) => {
    state.deleteBlog(id);
  };

  return (
    
      
"flex"       flexDirection= "column"       justifyContent= "flex-start"       alignItems= "center"       maxW= "1440px"       minH= "100vh"       m= "auto"     >         "100vh"         mt= "0rem"          bg={{ base: "transparent", md: "blackAlpha.400" }}         p={8}       >          "28px" fontWeight= "600" mb={4}>           Blog posts: {state.getCountBlog()}                              "content"             value={content}             onChange={(e) => setContent(e.target.value)}             errorBorderColor= "crimson"             placeholder= "Enter Quote"             borderInlineEndRadius={0}           />           {edit ? (              bg= "green"               color= "#fff"             >               Update                        ) : (              bg= "green" color= "#fff">               Add                        )}                             {data.length < 1 && (              "center">               No blog post found                        )}           {data &&             data.map((item, index) => (                "hidden"                 variant= "outline"                 my={4}               >                  "cover"                   maxW={{ base: "100%", sm: "200px" }}                   src= "https://images.unsplash.com/photo-1667489022797-ab608913feeb?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw5fHx8ZW58MHx8fHw%3D&auto=format&fit=crop&w=800&q=60"                   alt= "Caffe Latte"                 />                  "full">                                         "24px" fontWeight= "600" py= "2">                       {item.get(item).content}                                                            "flex" justifyContent= "flex-end" gap={4}>                      true);                         setUpdateId(item.get(item).id);                       }}                        bg= "blue"                       color= "#fff"                     >                       Edit                                           bg= "red"                       color= "#fff"                     >                       Delete                                                                                     ))}                        ); }; export default App;

我们在前面的代码块中创建了命名函数,并将函数从全局状态传递到每个函数中。只需使用item.get(item).content 或 item.value.content 在 Hookstate 中显示一个值。


image text 异步状态

Hookstate 可以轻松处理异步数据,执行 API 调用直至解析。异步数据可以全局存储,并可以从应用程序中的任何位置从存储中访问。

我们将使用下面的代码块创建一个异步状态,该状态将从 API 获取用户列表并在 App.js 组件中显示结果。

import { hookstate, useHookstate } from "@hookstate/core";
import axios from "axios";

const initialState = hookstate(
  {
    loading: false,
    users: [],
  }
);

export const useGlobalState = () => {
  const state = useHookstate(initialState);
  const resourcePath = "https://jsonplaceholder.typicode.com/users";

  return {
    loading: () => state.loading,
    getUsers: async () => {
    await axios.get(resourcePath).then((r) => state.users.set(r.data));
    state.loading.set(true)
    },
    fetchUsers: () => state.users,
  };
};

我们将用户添加到应用程序的初始状态,并使用上面的代码块将值设置为空数组。该数组将包含从 API 检索的所有用户的列表。我们还添加了 state loading,其默认值为 false。

接下来,创建了三个可以读取和修改状态的函数。加载函数读取加载状态;getUsers必须作为访问状态的承诺来处理。fetchUsers只是返回用户的当前状态。

import React, { useEffect, useState } from "react";
import {
  Box,
  Card,
  CardBody,
  CardFooter,
  Image,
  Stack,
  Text,
} from "@chakra-ui/react";
import { useGlobalState } from "./store";

const App = () => {
  const state = useGlobalState();
  const [user, setUser] = useState([]);

  useEffect(() => {
    state.getUsers();

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    if (state.loading().value === true) {
      setUser(state.fetchUsers());
    }
  }, [state]);

  return (
    
      
"flex"       flexDirection= "column"       justifyContent= "flex-start"       alignItems= "center"       maxW= "1440px"       minH= "100vh"       m= "auto"     >         "100vh"         mt= "0rem"          bg={{ base: "transparent", md: "blackAlpha.400" }}         p={8}       >           "28px" fontWeight= "600" mb={4}>           User Count: {user.length}                             {user.length < 1 && (              "center">               No user post found                        )}           {user &&             user.map((item, index) => (                "hidden"                 variant= "outline"                 my={4}               >                  "cover"                   maxW={{ base: "100%", sm: "200px" }}                   src= "https://images.unsplash.com/photo-1667489022797-ab608913feeb?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw5fHx8ZW58MHx8fHw%3D&auto=format&fit=crop&w=800&q=60"                   alt= "Caffe Latte"                 />                  "full">                                         "24px" fontWeight= "600" py= "2">                       {item.value.name}                                                            "flex"                     justifyContent= "flex-start"                     gap={4}                   >                      {item.value.email}                                                                ))}                        ); }; export default App;

和前面一样, getUsers 从全局状态初始化函数并将数据加载到用户中,然后 fetchUsers 仅当 loading 设置为 true 时才能成功检索用户列表。接下来,我们映射来自状态的数据 user 并使用 item.value.name 和item.value.email 来获取每个项目的值。


image text 开发工具

使用开发工具,你可以在 Hookstate 中检查应用程序的状态。它具有已知的最简单的配置;所需要做的就是将第二个参数传递给 hookstate,如下面的代码所示。这对生产应用程序没有不利影响。

...
import { devtools } from "@hookstate/devtools";

const initialState = hookstate(
  {
    loading: false,
    users: [],
  },
  devtools({ key: "my-state-label" })
);
...
image text 结尾

篇幅有限,除以上内容之外 Hookstate 还支持多种自定义扩展,如状态快照、状态校验、数据持久化等。本人使用 Hookstate 开发的体感是优于 redux 系列的。要了解有关 Hookstate 的更多信息,请访问官方文档。

最后觉得文章还不错,帮忙赞一个,多谢。

参考文献

https://hookstate.js.org/

https://blog.openreplay.com/state-management-in-react-with-hookstate/

- END -

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
菲军断指哥:被中国男足迷惑了!一交手兔子变老虎,剑桥大学变脸

菲军断指哥:被中国男足迷惑了!一交手兔子变老虎,剑桥大学变脸

大风文字
2024-06-20 12:38:19
2134名女性,0感染!艾滋病预防药传出大消息,只需半年注射一次,药厂股价应声暴涨

2134名女性,0感染!艾滋病预防药传出大消息,只需半年注射一次,药厂股价应声暴涨

每日经济新闻
2024-06-21 07:48:04
心知肚明!美国拒绝承认拱火两岸斗争,害怕地位被夺,人人皆知

心知肚明!美国拒绝承认拱火两岸斗争,害怕地位被夺,人人皆知

陆弃
2024-06-20 09:52:14
湖人正式确认,1换1交易完成,乔治没底牌了,英格拉姆交易被拒

湖人正式确认,1换1交易完成,乔治没底牌了,英格拉姆交易被拒

体坛大辣椒
2024-06-21 08:22:55
男子提前下班回家,妻子将其堵在门外连声质问:为啥不提前打招呼

男子提前下班回家,妻子将其堵在门外连声质问:为啥不提前打招呼

户外阿崭
2024-06-21 00:11:13
女排遇争议判罚 丁霞爆粗口怒骂韩国裁判曝光  难怪蔡斌不放弃她

女排遇争议判罚 丁霞爆粗口怒骂韩国裁判曝光 难怪蔡斌不放弃她

厝边人侃体育
2024-06-20 23:10:21
“爆改”永辉超市首日销售额暴增近14倍?胖东来:淘汰了80%产品,往好的方向发展,7月1日改造“新乡店”【附超市行业发展现状分析】

“爆改”永辉超市首日销售额暴增近14倍?胖东来:淘汰了80%产品,往好的方向发展,7月1日改造“新乡店”【附超市行业发展现状分析】

前瞻网
2024-06-20 16:53:11
大S模仿者去深圳麻六记,被工作人员拒绝入内,满脸落寞打道回府

大S模仿者去深圳麻六记,被工作人员拒绝入内,满脸落寞打道回府

郑丁嘉话
2024-06-20 14:16:30
范冰冰又给国人长脸了!一袭中式刺绣裙,让世界见证东方之雅韵

范冰冰又给国人长脸了!一袭中式刺绣裙,让世界见证东方之雅韵

八卦王者
2024-06-20 15:50:26
网传陈晓离婚,赵丽颖登上热搜,于正曾发文暗示,难道要再续前缘

网传陈晓离婚,赵丽颖登上热搜,于正曾发文暗示,难道要再续前缘

青栀伊人
2024-06-20 22:09:38
喝茶对心脏到底是好是坏?医生苦劝:4种茶,一口都不要喝

喝茶对心脏到底是好是坏?医生苦劝:4种茶,一口都不要喝

宋若讲故事
2023-01-18 21:38:26
女生私处「小花瓣」长什么样,才正常?

女生私处「小花瓣」长什么样,才正常?

喜马拉雅主播暮霭
2024-06-09 13:13:48
姜萍家院子成“网红打卡地”,村民称正常生活受影响

姜萍家院子成“网红打卡地”,村民称正常生活受影响

上游新闻
2024-06-20 12:05:18
安徽歙县2.7万余人受灾

安徽歙县2.7万余人受灾

界面新闻
2024-06-21 08:04:07
一直以为监狱里踩缝纫机是开玩笑,没想到里面的工种这么丰富

一直以为监狱里踩缝纫机是开玩笑,没想到里面的工种这么丰富

开玩笑的水母
2024-06-20 19:09:59
快船给哈登两份合同报价 2年7000万或4年1亿 不接受就去自由市场

快船给哈登两份合同报价 2年7000万或4年1亿 不接受就去自由市场

篮球话题团
2024-06-21 01:46:37
世界女排联赛总决赛打响,中国女排0比3不敌日本无缘四强

世界女排联赛总决赛打响,中国女排0比3不敌日本无缘四强

澎湃新闻
2024-06-20 19:22:28
注意!成都锦里西路周边临时交通管控

注意!成都锦里西路周边临时交通管控

封面新闻
2024-06-21 10:27:08
庐山会议时,毛泽东为何会对彭德怀不留情面?根本原因值得警醒

庐山会议时,毛泽东为何会对彭德怀不留情面?根本原因值得警醒

拙言问史
2024-05-04 22:19:24
国家社科基金项目成果:男人阴茎越短,智商越高

国家社科基金项目成果:男人阴茎越短,智商越高

必记本
2024-06-19 01:09:57
2024-06-21 11:58:44
君伟说
君伟说
分享职场故事
230文章数 48关注度
往期回顾 全部

科技要闻

王仲远:GPT4不是国内大模型的尽头

头条要闻

普京一天见了四位越南领导人 河内市委书记没有出现

头条要闻

普京一天见了四位越南领导人 河内市委书记没有出现

体育要闻

1-0"吊打"意大利 西班牙这就叫冠军相?

娱乐要闻

陈晓惹争议!被曝婚变离家出走冷暴力

财经要闻

普华永道,引火烧身

汽车要闻

领克纯电,来得不晚

态度原创

本地
房产
旅游
时尚
艺术

本地新闻

2024·合肥印象|用崭新视角对话城市发展

房产要闻

海棠湾!一所重量级国际学校真的来了!

旅游要闻

强降雨天气来袭:桂林部分景点关闭 酒店启动退改

黑色的透视单品,就选这6件!

艺术要闻

穿越时空的艺术:《马可·波罗》AI沉浸影片探索人类文明

无障碍浏览 进入关怀版