React 低代码项目:组件设计

React 低代码项目:组件设计

Date: February 6, 2025





React表单组件

**目标:**使用 Ant Design 表单组件,开发登录、注册、搜索功能

内容:

  • 使用 React 表单组件、受控组件
  • 使用 Ant Design 表单组件
  • 使用 表单组件的校验和错误提示,几种方案

注意事项:

  • 表单组件在 React 中比较特别,要单独学习(在HTML也一样)
  • 注意接受并理解“受控组件”,虽然看似繁琐


受控组件 vs 非受控组件

**受控组件:**值同步到 state,使用 value 属性

受控组件是指表单元素的值由 React 组件的状态(state 完全控制的组件。也就是说,表单的输入值存储在组件的状态中,任何用户输入都会触发状态更新,从而让组件重新渲染。

特点:

  • 受控组件的值总是由 React 状态(state)驱动
  • 表单控件(如 input, select, textarea)的值由 state 来管理,而不是通过 DOM 操作。
  • 用户在表单中的输入通过事件(如 onChange)更新组件的状态,进而影响输入框的值。

工作流程:

  1. 用户在表单控件中输入内容。
  2. onChange 事件触发,更新组件的 state
  3. React 重新渲染组件,更新表单控件的值。

Case:

import React, { useState } from 'react';const ControlledInput = () => {// 使用 state 来控制输入框的值const [inputValue, setInputValue] = useState('');// 处理输入框的变化const handleChange = (e) => {setInputValue(e.target.value);  // 更新 state};return (<div><label>输入框:<inputtype="text"value={inputValue}  // 受控组件的值来自 stateonChange={handleChange}  // 处理用户输入/></label><p>输入的值: {inputValue}</p></div>);
};export default ControlledInput;

解释:

  • value={inputValue}:输入框的值与 state 绑定。
  • onChange={handleChange}:每次用户输入时,handleChange 会更新 inputValue 状态,React 会触发重新渲染。

**非受控组件:**值不同步 state,使用 defaultValue 属性

概念:

在 React 中,非受控组件是指表单元素的值由 DOM 自身管理,而不是由 React 的 state 来控制。你可以使用 ref 来直接访问和修改表单元素的值。与受控组件不同,非受控组件不需要绑定 valueonChange 来处理输入数据。

与受控组件不同,非受控组件不需要将输入框的值绑定到 state,它直接操作 DOM。

Case:

import React, { useRef } from 'react';const UncontrolledInput = () => {const inputRef = useRef(); // 创建引用来访问输入框const handleSubmit = (e) => {e.preventDefault();alert('输入的内容:' + inputRef.current.value); // 使用 ref 获取输入的值};return (<form onSubmit={handleSubmit}><label>输入框:<input type="text" ref={inputRef} /> {/* 没有绑定 state */}</label><br /><button type="submit">提交</button></form>);
};export default UncontrolledInput;

受控组件与非受控组件的对比:

特性受控组件非受控组件
值来源值由组件的 state 控制值由 DOM 元素本身控制,通过 ref 获取
更新方式通过 onChange 更新 state通过 ref 获取 DOM 元素的当前值
优点- 组件状态与视图同步- 代码简单,适用于不需要实时控制的表单
- 可随时访问表单数据- 性能较好,避免了频繁的状态更新
缺点- 对于每个表单控件需要管理状态,代码较冗长- 不适合需要动态交互或表单验证的场景
适用场景- 动态表单数据交互(如验证、格式化等)- 简单的表单,数据获取仅在提交时才需要

总结:

React 推荐使用受控组件,看似繁琐,但更加可控

  • 受控组件:值由 React 状态控制,适合需要动态交互、验证、格式化等场景。
  • 非受控组件:值由 DOM 控制,适合简单表单或不需要频繁更新组件状态的场景。


搜索框开发

思考要点:

  • 搜索框的值应该传递到地址栏中。当其他组件需要使用时,可以通过该值来处理。

注意:不建议组件与组件之间直接传值,来实现状态切换。而是统一传递到地址栏,然后再获取。

http://ocalhost:3000/manage/ist
http://localhost:3000/manage/list?keyword=hello
http://localhost:3000/manage/list?keyword=hello&page=2

image.png

设计要点:

  • 传递搜索参数到URL(useNavigate)
  • URL搜索参数同步到搜索框(useSearchParams)
import React, { FC, useEffect, useState } from 'react'
import type { ChangeEvent } from 'react'
import { Input } from 'antd'
import { useNavigate, useLocation, useSearchParams } from 'react-router-dom'
import { LIST_SEARCH_PLACEHOLDER } from '../constant'const { Search } = Inputconst ListSearch: FC = () => {const nav = useNavigate()const { pathname } = useLocation()const [value, setValue] = useState('')const [searchParams] = useSearchParams()useEffect(() => {const keyword = searchParams.get(LIST_SEARCH_PLACEHOLDER) || ''setValue(keyword)// 每当 searchParams 变化时,更新 value}, [searchParams])function handleSearch(value: string) {nav({pathname,search: `${LIST_SEARCH_PLACEHOLDER}=${value}`,})}function handleChange(e: ChangeEvent<HTMLInputElement>) {setValue(e.target.value)}return (<Searchplaceholder="搜索"allowClearenterButton="搜索"size="middle"value={value}onChange={handleChange}onSearch={handleSearch}style={{ width: '260px' }}/>)
}export default ListSearch


注册登陆页开发

注册页开发

效果:

image.png

要点:

  • 表单校验实现
  • 细节:标签框长度设计

参考:标签框长度设计

Register.tsx

import React, { FC } from 'react'
import styles from './Register.module.scss'
import { Typography, Space, Form, Input, Button } from 'antd'
import { Link } from 'react-router-dom'
import { UserAddOutlined } from '@ant-design/icons'
import { LOGIN_PATHNAME } from '../router'const { Title } = Typographyconst Register: FC = () => {function onFinish(values: {username: stringpassword: stringconfirm: stringnickname: string}) {console.log('Success:', values)}return (<div className={styles.container}><div><Space><Title level={2}><UserAddOutlined /></Title><Title level={2}>注册新用户</Title></Space></div><div><FormlabelCol={{ span: 8 }}wrapperCol={{ span: 16 }}onFinish={onFinish}><Form.Itemlabel="用户名"name="username"rules={[{ required: true, message: '请输入你的用户名!' },{ min: 4, max: 20, message: '用户名长度在 4-20 之间' },{pattern: /^[a-zA-Z0-9_]+$/,message: '用户名只能由字母、数字和下划线组成',},]}><Input /></Form.Item><Form.Itemlabel="密码"name="password"rules={[{ required: true, message: '请输入你的密码!' }]}><Input.Password /></Form.Item><Form.Itemlabel="确认密码"name="confirm"dependencies={['password']}rules={[{ required: true, message: '请再次输入你的密码!' },({ getFieldValue }) => ({validator(_, value) {if (!value || getFieldValue('password') === value) {return Promise.resolve()}return Promise.reject('两次输入的密码不一致!')},}),]}><Input.Password /></Form.Item><Form.Itemlabel="昵称"name="nickname"rules={[{ required: true, message: '请输入你的昵称!' }]}><Input /></Form.Item><Form.Item wrapperCol={{ offset: 8, span: 16 }}><Space><Button type="primary" htmlType="submit">注册</Button><Link to={LOGIN_PATHNAME}>已有账户,请登陆</Link></Space></Form.Item></Form></div></div>)
}export default Register

登陆页开发

效果:

image.png

要点:

  • 用户名、密码记住存储实现
  • useForm Hook 实现表单值同步

Login.tsx

import React, { FC, useEffect } from 'react'
import styles from './Register.module.scss'
import { Typography, Space, Form, Input, Button, Checkbox } from 'antd'
import { Link } from 'react-router-dom'
import { UserAddOutlined } from '@ant-design/icons'
import { REGISTER_PATHNAME } from '../router'const { Title } = Typographyconst USERNAME_KEY = 'USERNAME'
const PASSWORD_KEY = 'PASSWORD'function rememberUser(username: string, password: string) {localStorage.setItem(USERNAME_KEY, username)localStorage.setItem(PASSWORD_KEY, password)
}function deleteUserFromLocalStorage() {localStorage.removeItem(USERNAME_KEY)localStorage.removeItem(PASSWORD_KEY)
}function getUserFromLocalStorage() {return {username: localStorage.getItem(USERNAME_KEY),password: localStorage.getItem(PASSWORD_KEY),}
}const Login: FC = () => {const [form] = Form.useForm() // 第三方 hookuseEffect(() => {const { username, password } = getUserFromLocalStorage()form.setFieldsValue({ username, password })}, [])const onFinish = (values: {username: stringpassword: stringremember: boolean}) => {const { remember } = values || {}if (remember) {rememberUser(values.username, values.password)} else {deleteUserFromLocalStorage()}}return (<div className={styles.container}><div><Space><Title level={2}><UserAddOutlined /></Title><Title level={2}>登陆</Title></Space></div><div><FormlabelCol={{ span: 8 }}wrapperCol={{ span: 16 }}onFinish={onFinish}initialValues={{ remember: true }}form={form}><Form.Itemlabel="用户名"name="username"rules={[{ required: true, message: '请输入你的用户名!' }]}><Input /></Form.Item><Form.Itemlabel="密码"name="password"rules={[{ required: true, message: '请输入你的密码!' }]}><Input.Password /></Form.Item><Form.Itemname="remember"valuePropName="checked"wrapperCol={{ offset: 8, span: 16 }}><Checkbox>记住我</Checkbox></Form.Item><Form.Item wrapperCol={{ offset: 8, span: 16 }}><Space size="large"><Button type="primary" htmlType="submit">登陆</Button><Link to={REGISTER_PATHNAME}>注册新用户</Link></Space></Form.Item></Form></div></div>)
}export default Login


参考工具:表单校验

  • Ant Design rules
  • React-hook-form
  • Formik

封装细节

缩短请求参数

封装 useLoadQuestionListData 时,对于 opt 参数,可以不填写默认值,从而缩短请求参数。

**对比:**填写默认参数

image.png

不填写默认参数

image.png

**请求对比:**左边为填写默认参数,右边为不填写

image.png


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/17905.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue-plugin-hiprint (vue2

页面效果 <template><div><div class="d-flex flex-column mt5"><div class="d-flex flex-row " style="margin-bottom: 10px;justify-content: center;"><!-- 纸张大小 A3、A4 等 --><div class="paper…

C++17 中的 std::reduce:详细教程

文章目录 1. 简介2. 函数签名3. 使用场景3.1 简单的累加操作3.2 自定义归并操作3.3 并行计算的性能优势 4. 注意事项4.1 归并操作的结合律和交换律4.2 默认值的使用 5. 总结 1. 简介 std::reduce 是 C17 标准库中引入的一个算法&#xff0c;用于对范围内的元素进行归并操作。它…

kafka介绍,kafka集群环境搭建,kafka命令测试,C++实现kafka客户端

目录 kafka介绍kafka集群环境搭建zookeeper安装与配置kafka安装与配置 kafka命令测试C实现kafka客户端librdkafka库编译新版本cmake编译cppkafka库编译C实现kafka生产者和消费者客户端 kafka介绍 定义与概述 Apache Kafka 是一个开源的分布式流处理平台&#xff0c;最初由 Lin…

华为云+硅基流动使用Chatbox接入DeepSeek-R1满血版671B

华为云硅基流动使用Chatbox接入DeepSeek-R1满血版671B 硅基流动 1.1 注册登录 1.2 实名认证 1.3 创建API密钥 1.4 客户端工具 OllamaChatboxCherry StudioAnythingLLM 资源包下载&#xff1a; AI聊天本地客户端 接入Chatbox客户端 点击设置 选择SiliconFloW API 粘贴1.3创…

阿里云百炼平台对接DeepSeek官方文档

目录 1、支持的模型 2、快速开始 2.1、OpenAI兼容 2.1.1、python示例代码 返回结果 2.1.2、Node.js示例代码 返回结果 2.1.3、HTTP示例代码 返回结果 2.2、DashScope 2.2.1、python示例代码 返回结果 2.2.2、java示例代码 返回结果 2.2.3、HTTP代码示例 返回结…

【深度强化学习】策略梯度算法:REINFORCE

策略梯度 强化学习算法进阶 Q-learning、DQN 及 DQN 改进算法都是基于价值&#xff08;value-based&#xff09;的方法&#xff0c;其中 Q-learning 是处理有限状态的算法&#xff0c;而 DQN 可以用来解决连续状态的问题。在强化学习中&#xff0c;除了基于值函数的方法&#…

DeepSeek接口联调(postman版)

第一步&#xff1a;获取API key 获取APIkeys链接https://platform.deepseek.com/api_keys 点击创建 API key 即可免费生成一个key值&#xff0c;别忘记保存。 第二步&#xff1a;找到deepseek官方接口文档 文档地址&#xff1a;https://api-docs.deepseek.com/zh-cn/ 第三步…

Sublime Text 3 中的 Pylinter 配置

在 Sublime Text 3 中配置 Pylinter&#xff08;如 pylint&#xff09;来进行 Python 代码静态分析&#xff0c;可以帮助你提升代码质量、检测潜在的错误、强制遵守编码标准等。为了在 Sublime Text 3 中配置 pylint&#xff0c;你需要确保 pylint 已安装&#xff0c;并设置好相…

LC-搜索二维矩阵II、相交链表、反转链表、回文链表、环形链表、环形链表ll

搜索二维矩阵II 方法&#xff1a;从右上角开始搜索 我们可以从矩阵的右上角开始进行搜索。如果当前元素 matrix[i][j] 等于 target&#xff0c;我们直接返回 true。如果 matrix[i][j] 大于 target&#xff0c;说明 target 只能出现在左边的列&#xff0c;所以我们将列指针向左…

支持列表拖拽嵌套,AI流式输出的多模态文档编辑器flowmix/docx: 全面升级

hi, 大家好, 我是徐小夕. 马上又到周五了, 最近也收到很多用户对 flowmix/docx 多模态文档编辑器的反馈&#xff0c;我们也做了一波新功能的升级&#xff0c;今天就和大家分享一下 flowmix/docx 多模态文档编辑器的最新更新. 演示地址: https://flowmix.turntip.cn/docx 以下是…

服务器中部署大模型DeepSeek-R1 | 本地部署DeepSeek-R1大模型 | deepseek-r1部署详细教程

0. 部署前的准备 首先我们需要足够算力的机器&#xff0c;这里我在vultr中租了有一张A16显卡一共16GB显存的服务器作为演示。部署的模型参数为14b的。如果需要部署满血版本671b的&#xff0c;需要更大的算力支持&#xff0c;这里由于是个人资金有限&#xff0c;就演示14b的部署…

Linux软件编程(1)

1.总述&#xff1a; 2.标准io与文件io 标准C库提供的一套文件操作接口&#xff1b; Linux内核为Linux操作系统提供的一套文件操作接口。 3.函数接口&#xff1a; 注意 &#xff1a;什么是文件流&#xff1f; 数据从文件流入和流出体现的字节流。 注意&#xff1a;od -c 文件…

网页五子棋——通用模块

目录 项目创建 通用功能模块 错误码 自定义异常类 CommonResult jackson 加密工具 项目创建 使用 idea 创建 SpringBoot 项目&#xff0c;并引入相关依赖&#xff1a; 配置 MyBatis&#xff1a; 编辑 application.yml&#xff1a; spring:datasource: # 数据库连接配…

【工具】在idea运行go后端

场景&#xff1a;从gitee仓库下载一个go语言前后端分离项目&#xff0c;想跑通前后端 ---------------------------------------------------------------------------------------------------------------------- 后端 1.下载插件 在idea的setting里面输入go&#xff0c;…

通达信如何导出以往的分时数据

1当天分时数据的导出 以梦网科技为例&#xff0c;在分笔交易上面右键&#xff0c;选择“放大”&#xff0c;放大后选择“选项”&#xff0c;选择“数据导出”&#xff0c;弹出界面中修改路径与文件名即可。 2以往数据的导出 以梦网科技为例&#xff0c;今天是2025年2月14号…

【面试题系列】Java 多线程面试题深度解析

本文涉及Java 多线程面试题&#xff0c;从基础到高级&#xff0c;希望对你有所帮助&#xff01; 一、基础概念类 1. 请简述 Java 中线程的几种状态及其转换条件 题目分析&#xff1a;这是多线程基础中的基础&#xff0c;考查对线程生命周期的理解&#xff0c;在多线程编程中&…

Java Virtual Machine(JVM)

JVM跨平台原理 跨平台&#xff1a;一次编译&#xff0c;到处运行 本质&#xff1a;不同操作系统上运行的JVM不一样&#xff0c;只需要把java程序编译成一份字节码文件&#xff0c;JVM执行不同的字节码文件。 Java是高级语言&#xff0c;提前编译一下&#xff08;变成字节码文件…

duckdb导出Excel和导出CSV速度测试

运行duckdb数据库 D:>duckdb v1.2.0 5f5512b827 Enter “.help” for usage hints. Connected to a transient in-memory database. Use “.open FILENAME” to reopen on a persistent database. 生成模拟数据&#xff0c;10个列&#xff0c;100万行数据&#xff1b; --…

TCP/IP参考模型和网络协议

由于国防部担心他们一些重要的主机、路由器和互联网关可能会突然崩溃&#xff0c;所以网络必须实现的另一目标是网络不受子网硬件损失的影响&#xff0c;已经建立的会话不会被取消&#xff0c;而且整个体系结构必须相当灵活。 TCP/IP是一组用于实现网络互连的通信协议。Interne…

uniapp商场之订单模块【订单列表】

文章目录 前言一、准备静态结构(分包)二、Tabs滑动切换1.Tabs文字渲染2.点文字高亮切换3.swiper滑动切换三、Tabs页面跳转高亮四、订单列表渲染1.封装列表组件2.订单状态父传子3.封装请求API4.准备请求参数5.初始化调用6.页面渲染五、订单支付1.页面条件渲染2.事件绑定前言 …