当前位置: 首页 > news >正文

0302useState-hooks-react-仿低代码平台项目

文章目录

    • 1 useState
      • 1.1 说明
        • 返回
      • 1.2 示例
      • 1.3 数据类型
    • 2 state
      • 2.1 概述
      • 2.2 state特点
    • 3 state重构问卷
    • 4 immer
    • 结语

1 useState

useState 是一个 React Hook,它允许你向组件添加一个 状态变量。

1.1 说明

  • 语法
const [state, setState] = useState(initialState)
  • 参数 initialState: 你希望 state 初始化的值。它可以是任何类型的值,但对于函数有特殊的行为。在初始渲染后,此参数将被忽略。
  • 如果传递函数作为 initialState,则它将被视为 初始化函数。它应该是纯函数,不应该接受任何参数,并且应该返回一个任何类型的值。当初始化组件时,React 将调用你的初始化函数,并将其返回值存储为初始状态。
返回

useState 返回一个由两个值组成的数组:

  1. 当前的 state。在首次渲染时,它将与你传递的 initialState 相匹配。
  2. set 函数,它可以让你将 state 更新为不同的值并触发重新渲染。

1.2 示例

如下是一个简单的点击按钮累加的示例:

import { useState } from "react";
function Acc() {
  // 普通js变量无法触发组件更新
  // let count = 0;
  //useState可以触发组件更新
  const [count, setCount] = useState(0);

  // 点击累加
  function add() {
    setCount(count + 1);
  }

  return (
    <>
      <button onClick={add}> click to accumulate:{count} </button>
    </>
  );
}

export default Acc;

普通js变量无法触发组件更新,如下图所示:在这里插入图片描述

使用useState实现页面组件更新,如下图所示:在这里插入图片描述

1.3 数据类型

useState(0)
useState('a')
useState({"a": 1, "b": 2})
useState([1,2,3])
  • xxx类型没有限制,可以是任意类型

2 state

2.1 概述

组件可以拥有状态(state),它是组件数据的私有部分,可以用来管理动态数据。

状态仅适用于类组件,或者使用 React 的 Hook 时可以在函数组件中使用。

React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。

React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。

以下实例创建一个名称扩展为 React.Component 的 ES6 类,在 render() 方法中使用 this.state 来修改当前的时间。

添加一个类构造函数来初始化状态 this.state,类组件应始终使用 props 调用基础构造函数。


2.2 state特点

  • State异步更新,示例代码如下

    import { FC, useState } from "react";
    const StateDemo01: FC = () => {
      //useState可以触发组件更新
      const [count, setCount] = useState(0);
      const [name, setName] = useState("张三");
    
      // 点击累加
      function add() {
        setCount(count + 1);
        console.log(count);
    
        //如果一个变量不用于jsx中显示,不要用useState管理它,用useRef.
        setName("李四");
      }
    
      return (
        <>
          <button onClick={add}> click to accumulate:{count} </button>
        </>
      );
    };
    
    export default StateDemo01;
    

打印结果如下所示:在这里插入图片描述

  • state可能会被合并,

      // 点击累加
      function add() {
        setCount(count + 1);
        setCount(count + 1);
        setCount(count + 1);
        setCount(count + 1);
        setCount(count + 1);
        console.log(count);
    
        //如果一个变量不用于jsx中显示,不要用useState管理它,用useRef.
        // setName("李四");
      }
    

    页面结果如上所示,如果想要不被合并,参数传入函数,代码如下:

        setCount((count) => count + 1);
    
  • 不可变数据,如需修改数据,需要传入新值

    import { FC, useState } from "react";
    const StateDemo02: FC = () => {
      //useState可以触发组件更新
      const [userInfo, setUserInfo] = useState({ name: "张三", age: 20 });
    
      // 点击累加
      function edit() {
        // 不可变数据,不去修改state的值,而是传入一个新的值或者返回一个新值的函数或者表达式
        // setUserInfo({ name: "张三", age: 21 }); // 全量语法
        setUserInfo({ ...userInfo, age: 21 }); // 结构语法
      }
    
      return (
        <>
          <h3>state:不可变数据</h3>
          <div> {JSON.stringify(userInfo)} </div>
          <button onClick={edit}> 修改年龄 </button>
        </>
      );
    };
    
    export default StateDemo02;
    
    

    修改数组

    setXxx([...arr, 5])
    setXxx(arr.concat(5))
    

3 state重构问卷

  • state替换文件列表

    import { FC, useState } from "react";
    
    import QuestionCard from "./QuestionCard";
    const List2: FC = () => {
      //列表页
    
      //问卷列表数据
      const questions = [
        { id: "q1", title: "问卷1", isPublished: false },
        { id: "q2", title: "问卷2", isPublished: false },
        { id: "q3", title: "问卷3", isPublished: true },
        { id: "q4", title: "问卷4", isPublished: false },
        { id: "q5", title: "问卷5", isPublished: true },
      ];
    
      const [questionList, setQuestionList] = useState(questions);
    
      const r = Math.random().toString().slice(-3);
    
    
      return (
        <div>
          <h1>问卷列表页</h1>
          <div>
            {questionList.map((q) => {
              const { id, title, isPublished } = q;
              return (
                <QuestionCard
                  key={id}
                  id={id}
                  title={title}
                  isPublished={isPublished}
                />
              );
            })}
          </div>
        </div>
      );
    };
    
    export default List2;
    
    
  • 新增问卷

    import { FC, useState } from "react";
    
    import QuestionCard from "./QuestionCard";
    const List2: FC = () => {
      //列表页
    
      //问卷列表数据
      const questions = [
        { id: "q1", title: "问卷1", isPublished: false },
        { id: "q2", title: "问卷2", isPublished: false },
        { id: "q3", title: "问卷3", isPublished: true },
        { id: "q4", title: "问卷4", isPublished: false },
        { id: "q5", title: "问卷5", isPublished: true },
      ];
    
      const [questionList, setQuestionList] = useState(questions);
    
      const r = Math.random().toString().slice(-3);
    
      // 新增问卷
      function add() {
        setQuestionList([
          ...questionList,
          {
            id: "q" + r,
            title: "问卷" + r,
            isPublished: false,
          },
        ]);
      }
    
      return (
        <div>
          <h1>问卷列表页</h1>
          <div>
            {questionList.map((q) => {
              const { id, title, isPublished } = q;
              return (
                <QuestionCard
                  key={id}
                  id={id}
                  title={title}
                  isPublished={isPublished}
                />
              );
            })}
          </div>
          <div>
            <button onClick={add}>新增问卷</button>
          </div>
        </div>
      );
    };
    
    export default List2;
    

    效果如下所示:在这里插入图片描述

    • 删除问卷

    List2.tsx代码如下:

    import { FC, useState } from "react";
    
    import QuestionCard from "./components/QuestionCard";
    const List2: FC = () => {
      //列表页
    
      //问卷列表数据
      const questions = [
        { id: "q1", title: "问卷1", isPublished: false },
        { id: "q2", title: "问卷2", isPublished: false },
        { id: "q3", title: "问卷3", isPublished: true },
        { id: "q4", title: "问卷4", isPublished: false },
        { id: "q5", title: "问卷5", isPublished: true },
      ];
    
      const [questionList, setQuestionList] = useState(questions);
    
      const r = Math.random().toString().slice(-3);
    
      // 新增问卷
      function add() {
        setQuestionList([
          ...questionList,
          {
            id: "q" + r,
            title: "问卷" + r,
            isPublished: false,
          },
        ]);
      }
    
      // 删除问卷
      function deleteQuestion(id: string) {
        setQuestionList(
          questionList.filter((q) => {
            return q.id !== id;
          })
        );
      }
    
      return (
        <div>
          <h1>问卷列表页</h1>
          <div>
            {questionList.map((q) => {
              const { id, title, isPublished } = q;
              return (
                <QuestionCard
                  key={id}
                  id={id}
                  title={title}
                  isPublished={isPublished}
                  deleteQuestion={deleteQuestion}
                />
              );
            })}
          </div>
          <div>
            <button onClick={add}>新增问卷</button>
          </div>
        </div>
      );
    };
    
    export default List2;
    

    QuestionCard.tsx代码如下:

    import React, { FC } from "react";
    
    import "./QuestionCard.css";
    
    type PropsType = {
      id: string;
      title: string;
      isPublished: boolean;
      deleteQuestion: (id: string) => void;
    };
    
    const QuestionCard: FC<PropsType> = (props) => {
      const { id, title, isPublished, deleteQuestion } = props;
    
      //编辑问卷
      function edit(id: string) {
        console.log("id:", id);
      }
    
      // 删除问卷
      function del(id: string) {
        deleteQuestion(id);
      }
    
      return (
        <div key={id} className="list-item">
          <strong>{title}</strong>
          &nbsp;
          {/* 条件判断 */}
          {isPublished ? (
            <span style={{ color: "green" }}>已发布</span>
          ) : (
            <span>未发布 </span>
          )}
          &nbsp;
          <button onClick={() => edit(id)}>编辑问卷</button>
          &nbsp;
          <button onClick={() => del(id)}>删除问卷</button>
        </div>
      );
    };
    
    export default QuestionCard;
    

    页面效果如下图所示:在这里插入图片描述

  • 发布问卷

List2.tsx代码如下:

import { FC, useState } from "react";

import QuestionCard from "./components/QuestionCard";
const List2: FC = () => {
  //列表页

  //问卷列表数据
  const questions = [
    { id: "q1", title: "问卷1", isPublished: false },
    { id: "q2", title: "问卷2", isPublished: false },
    { id: "q3", title: "问卷3", isPublished: true },
    { id: "q4", title: "问卷4", isPublished: false },
    { id: "q5", title: "问卷5", isPublished: true },
  ];

  const [questionList, setQuestionList] = useState(questions);

  const r = Math.random().toString().slice(-3);

  // 新增问卷
  function add() {
    setQuestionList([
      ...questionList,
      {
        id: "q" + r,
        title: "问卷" + r,
        isPublished: false,
      },
    ]);
  }

  // 删除问卷
  function deleteQuestion(id: string) {
    setQuestionList(
      questionList.filter((q) => {
        return q.id !== id;
      })
    );
  }

  // 删除问卷
  function publishQuestion(id: string) {
    setQuestionList(
      questionList.map((q) => {
        if (q.id !== id) {
          return q;
        }
        return {
          ...q,
          isPublished: true,
        };
      })
    );
  }

  return (
    <div>
      <h1>问卷列表页</h1>
      <div>
        {questionList.map((q) => {
          const { id, title, isPublished } = q;
          return (
            <QuestionCard
              key={id}
              id={id}
              title={title}
              isPublished={isPublished}
              deleteQuestion={deleteQuestion}
              publishQuestion={publishQuestion}
            />
          );
        })}
      </div>
      <div>
        <button onClick={add}>新增问卷</button>
      </div>
    </div>
  );
};

export default List2;

QuestionCard.tsx代码如下:

import React, { FC } from "react";

import "./QuestionCard.css";

type PropsType = {
  id: string;
  title: string;
  isPublished: boolean;
  deleteQuestion?: (id: string) => void;
  publishQuestion?: (id: string) => void;
};

const QuestionCard: FC<PropsType> = (props) => {
  const { id, title, isPublished, deleteQuestion, publishQuestion } = props;

  //编辑问卷
  function edit(id: string) {
    console.log("id:", id);
  }

  // 删除问卷
  function del(id: string) {
    deleteQuestion && deleteQuestion(id);
  }

  // 发布问卷
  function publish(id: string) {
    publishQuestion && publishQuestion(id);
  }

  return (
    <div key={id} className="list-item">
      <strong>{title}</strong>
      &nbsp;
      {/* 条件判断 */}
      {isPublished ? (
        <span style={{ color: "green" }}>已发布</span>
      ) : (
        <span>未发布 </span>
      )}
      &nbsp;
      <button onClick={() => edit(id)}>编辑问卷</button>
      &nbsp;
      <button onClick={() => del(id)}>删除问卷</button>
      &nbsp;
      <button onClick={() => publish(id)}>发布问卷</button>
    </div>
  );
};

export default QuestionCard;

4 immer

如果你的 state 有多层的嵌套,你或许应该考虑 将其扁平化。但是,如果你不想改变 state 的数据结构,你可能更喜欢用一种更便捷的方式来实现嵌套展开的效果。Immer 是一个非常流行的库,它可以让你使用简便但可以直接修改的语法编写代码,并会帮你处理好复制的过程。通过使用 Immer,你写出的代码看起来就像是你“打破了规则”而直接修改了对象:

immer的使用说明参考下面连接2,这里用immer重构问卷,List2.tsx代码如下:

import { FC, useState } from "react";
import { useImmer } from "use-immer";

import QuestionCard from "./components/QuestionCard";
const List2: FC = () => {
  //列表页

  //问卷列表数据
  const questions = [
    { id: "q1", title: "问卷1", isPublished: false },
    { id: "q2", title: "问卷2", isPublished: false },
    { id: "q3", title: "问卷3", isPublished: true },
    { id: "q4", title: "问卷4", isPublished: false },
    { id: "q5", title: "问卷5", isPublished: true },
  ];

  const [questionList, updateQuestionList] = useImmer(questions);

  const r = Math.random().toString().slice(-3);

  // 新增问卷
  function add() {
    updateQuestionList((draft) => {
      draft.push({
        id: "q" + r,
        title: "问卷" + r,
        isPublished: false,
      });
    });
  }

  // 删除问卷
  function deleteQuestion(id: string) {
    updateQuestionList((draft) => {
      const index = draft.findIndex((q) => q.id === id);
      draft.splice(index, 1);
    });
  }

  // 发布问卷
  function publishQuestion(id: string) {
    updateQuestionList((draft) => {
      const q = draft.find((q) => q.id === id);
      q && (q.isPublished = true);
    });
  }

  return (
    <div>
      <h1>问卷列表页</h1>
      <div>
        {questionList.map((q) => {
          const { id, title, isPublished } = q;
          return (
            <QuestionCard
              key={id}
              id={id}
              title={title}
              isPublished={isPublished}
              deleteQuestion={deleteQuestion}
              publishQuestion={publishQuestion}
            />
          );
        })}
      </div>
      <div>
        <button onClick={add}>新增问卷</button>
      </div>
    </div>
  );
};

export default List2;

结语

❓QQ:806797785

⭐️仓库地址:https://gitee.com/gaogzhen

⭐️仓库地址:https://github.com/gaogzhen

[1]useState[CP/OL].

[2]使用 Immer 编写简洁的更新逻辑[CP/OL].

http://www.dtcms.com/a/112648.html

相关文章:

  • AingDesk是一款简单好用的AI助手,支持知识库、模型 API、分享、联网搜索、智能体,它正在迅速发展和改进
  • 电机控制学习路线
  • SpringCloud(25)——Stream介绍
  • 4.4 力扣|59螺旋矩阵II
  • AI与Python在地球科学多源数据交叉融合中的前沿
  • MCP(模型上下文协议)入门指南:用Web开发的视角理解下一代AI引擎
  • 集合与容器:List、HashMap(II)
  • 用 Docker Compose 与 Nginx 反向代理部署 Vikunja 待办事项管理系统
  • Leetcode 135 -- 贪心 | 拓扑排序
  • 【多线程-第四天-自己模拟SDWebImage的下载图片功能-下载操作管理类 Objective-C语言】
  • 如何排查、定位 SQL 慢查询及其优化策略
  • 16进制在蓝牙传输中的应用
  • 检查 Python 中的可迭代对象是否相等
  • Bethune X 6发布:为小规模数据库环境打造轻量化智能监控巡检利器
  • 字符串-JS
  • 基于 Hough 变换的直线检测2025.4.1
  • 大数据笔试题_第一阶段配套笔试题01
  • 浅谈AI落地 - 文章推荐 - 混合推荐模型
  • 【CF】Day24——Codeforces Round 994 (Div. 2) D
  • 常用性能指标(metrics)
  • 理解OSPF 特殊区域Stub和各类LSA特点
  • leetcode-链表+动规
  • idea如何让打开的文件名tab多行显示
  • Android studio进阶教程之(二)--如何导入高德地图
  • 超便捷语音转文字工具CapsWriter-Offline本地部署与远程使用全流程
  • 如何快速入门物联网单片机开发?
  • windows如何安装wkhtmltoimage 给PHP使用根据HTML生成图片
  • Mysql 中的 binlog、redolog、undolog
  • LayaAir3.3.0-beta.3重磅更新!Spine4.2、2D物理、UI系统、TileMap等全面升级!
  • 青少年编程与数学 02-015 大学数学知识点 09课题、专业相关性分析