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

React19学习-初体验

升级react19版本

  1. 安装
npm install react@beta react-dom@beta

如果使用ts则需要在package.json中添加。等正式版发布直接可以使用@types/react

  "overrides": {"@types/react": "npm:types-react@beta","@types/react-dom": "npm:types-react-dom@beta"}

官方文档

初始化项目

  1. npm create vite 选vanilla 和 ts
  2. 配置vite.config.ts
import {defineConfig} from "vite";
import react from '@vitejs/plugin-react';
/** @type {import('vite').UserConfig} */
export default {plugins:[react()]
}
  1. 安装依赖,如下package.json文件
{"name": "react19_exp","private": true,"version": "0.0.0","type": "module","scripts": {"dev": "vite","build": "tsc && vite build","preview": "vite preview"},"devDependencies": {"@types/node": "^20.12.10","@vitejs/plugin-react": "^4.2.1","typescript": "^5.2.2","vite": "^5.2.0"},"dependencies": {"@types/react": "npm:types-react@beta","@types/react-dom": "npm:types-react-dom@beta","react": "^19.0.0-beta-b498834eab-20240506","react-dom": "^19.0.0-beta-b498834eab-20240506"},"overrides": {"@types/react": "npm:types-react@beta","@types/react-dom": "npm:types-react-dom@beta"}
}
  1. 配置tsconfig.json
{"compilerOptions": {"target": "ES2020","useDefineForClassFields": true,"module": "ESNext","lib": ["ES2020", "DOM", "DOM.Iterable"],"skipLibCheck": true,/* Bundler mode */"moduleResolution": "bundler","allowImportingTsExtensions": true,"resolveJsonModule": true,"isolatedModules": true,"noEmit": true,/* Linting */"strict": true,"noUnusedLocals": true,"noUnusedParameters": true,"noFallthroughCasesInSwitch": true,"jsx": "react-jsx"},"include": ["src"],"references": [{ "path": "./tsconfig.node.json" }]/*tsconfig.node.json{"compilerOptions": {"composite": true,"skipLibCheck": true,"module": "ESNext","moduleResolution": "bundler","allowSyntheticDefaultImports": true,"strict": true},"include": ["vite.config.ts"]}
*/
}
  1. 之后将项目中的ts可以改为tsx启动项目即可

react19新特性体验

表单相关Hooks

状态突变

什么是状态突变?状态突变是指系统或对象的状态在某个时间点发生突然、不可预测的变化。
例如,当用户提交表单以更改其姓名时,将发出 API 请求,然后处理响应。过去,需要手动处理挂起状态、错误、乐观更新和顺序请求。过去使用方式代码示例

function UpdateName({}) {const [name, setName] = useState("");const [error, setError] = useState(null);const [isPending, setIsPending] = useState(false);const handleSubmit = async () => {setIsPending(true);const error = await updateName(name);setIsPending(false);if (error) {setError(error);return;} redirect("/path");};return (<div><input value={name} onChange={(event) => setName(event.target.value)} /><button onClick={handleSubmit} disabled={isPending}>Update</button>{error && <p>{error}</p>}</div>);
}

现在React提供了useTransition钩子,19使用示例

import {useState, useTransition} from "react";function updateName(name:string):Promise<string>{return new Promise((r)=>{setTimeout(()=>{if (!name)r("name不能为空")},2000)})
}export default ()=>{const [name, setName] = useState("");const [error, setError] = useState<string|null>(null);const [isPending, startTransition] = useTransition();const handleSubmit = () => {startTransition(async () => {const error = await updateName(name);if (error) {setError(error);return;}})};const renderLoading = ()=>{return <div className="loader"></div>}return (<div><input value={name} onChange={(event) => setName(event.target.value)}/>{isPending && renderLoading()}<button onClick={handleSubmit} disabled={isPending}>Update</button>{error && <p>{error}</p>}</div>)
}

效果展示
请添加图片描述

表单提交状态+行为useActionState

useActionState 接受一个函数(“Action”),并返回一个包装的 Action 进行调用。调用包装的 Action 时, useActionState 将 Action 的最后一个结果返回为data作为state的值 ,并将 Action 的挂起状态返回 pending

//函数签名
useActionState<State,Payload>(action: (state: Awaited<State>,payload: Payload) => State | Promise<State>,//表单提交行为initialState: Awaited<State>, // 初始表单的值permalink?: string,  // 目前不太了解,推测是表单提交后达到某个条件跳转到该链接上。有明白的小伙伴可以评论区留言
): [state: Awaited<State>, dispatch: (payload: Payload) => void, isPending: boolean];

示例

import {useActionState, useEffect} from "react";
function updateName(name:string):Promise<string>{return new Promise((r)=>{setTimeout(()=>{if (!name)r("name不能为空")r(name)},2000)})
}
export default ()=>{const [state, submitAction, isPending] = useActionState<string>(async (previousState:string, formData) => {const state = await updateName(formData.get("name"));// handle successreturn state;},"初始name值",);return (<form action={submitAction}><input type="text" name="name" /><button type="submit" disabled={isPending}>Update</button>{isPending && <div className="loader"></div>}{state && <p style={{color:"green"}}>{state}</p>}</form>);
}

请添加%图片描述

获取父组件表单状态useFormStatus

该Hooks为Form下面的子组件提供form状态信息,让我们不依赖父组件注入的Context就能获取到父组件的表单状态。

子组件

import {useFormStatus} from "react-dom";export default ()=>{const {pending} = useFormStatus();return <button type="submit" disabled={pending} >提交表单</button>
}

父组件部分代码展示

 <form action={submitAction}><input type="text" name="name" /><ExpUseFormStatus></ExpUseFormStatus>{isPending && <div className="loader"></div>}{state && <p style={{color:"green"}}>{state}</p>}</form>

效果展示请添加图片描述

乐观更新useOptimistic

有时候有些结果99%会成功,我们希望让用户尽快看到页面展示效果。可以采用该钩子。
子组件

import {useOptimistic} from "react";
interface Props{currentName:stringonUpdateName:(name:string)=>void
}
function updateName(name:string):Promise<string>{return new Promise((r)=>{setTimeout(()=>{if (!name)r("name不能为空")r(name)},2000)})
}
export default({currentName, onUpdateName}:Props)=> {const [optimisticName, setOptimisticName] = useOptimistic(currentName);const submitAction = async (formData: { get: (arg0: string) => any; }) => {const newName = formData.get("name");setOptimisticName(newName);const updatedName = await updateName(newName);onUpdateName(updatedName);};return (<form action={submitAction}><p>Your name is(currentName):<span style={{color:"green"}}>{currentName}</span> </p><p>Your name is(optimisticName): {optimisticName}</p><p><label>Change Name:</label><inputtype="text"name="name"disabled={currentName !== optimisticName}/></p><button type="submit">提交</button></form>);
}

父组件

export default ()=>{const [currentName, setCurrentName] = useState("fancy")return (<><ExpUseOptimistic currentName={currentName} onUpdateName={(name)=>setCurrentName(name)}></ExpUseOptimistic></>)
}

结果展示请添加图片描述

其他

use

use Hook让我们可以读取Context和Promise的值并且可以在循环和条件语句(如 if)中调用 use。但需要注意的是,调用 use 的函数仍然必须是一个组件或 Hook。

import { use } from 'react';function MessageComponent({ messagePromise }) {const message = use(messagePromise);const theme = use(ThemeContext);// ...

ref

以后不需要forward ref做转发了

function MyInput({placeholder, ref}) {return <input placeholder={placeholder} ref={ref} />
}<MyInput ref={ref} />

ref的清理函数,当组件卸载时,React 将调用从回调返回的 ref 清理函数。这适用于 DOM 引用、类组件引用和 useImperativeHandle .

<inputref={(ref) => {// ref created// NEW: return a cleanup function to reset// the ref when element is removed from DOM.return () => {// ref cleanup};}}
/>

Context 不再需要<Context.Provider>

const ThemeContext = createContext('');function App({children}) {return (<ThemeContext value="dark">{children}</ThemeContext>);  
}

支持在组件中编写Meta标签

当 React 渲染这个组件时,它会看到 <title> <link><meta> 标签,并自动将它们提升到文档 <head> 部分。通过本机支持这些元数据标记,我们能够确保它们适用于仅限客户端的应用、流式处理 SSR 和服务器组件。

function BlogPost({post}) {return (<article><h1>{post.title}</h1><title>{post.title}</title><meta name="author" content="Josh" /><link rel="author" href="https://twitter.com/joshcstory/" /><meta name="keywords" content={post.keywords} /><p>Eee equals em-see-squared...</p></article>);
}

支持预加载资源

文档
在初始文档加载和客户端更新期间,告知浏览器可能需要尽早加载的资源可能会对页面性能产生巨大影响。React 19 包含许多用于加载和预加载浏览器资源的新 API,以便尽可能轻松地构建出色的体验,而不会因资源加载效率低下而受到阻碍。

import { prefetchDNS, preconnect, preload, preinit } from 'react-dom'
function MyComponent() {preinit('https://.../path/to/some/script.js', {as: 'script' }) // loads and executes this script eagerlypreload('https://.../path/to/font.woff', { as: 'font' }) // preloads this fontpreload('https://.../path/to/stylesheet.css', { as: 'style' }) // preloads this stylesheetprefetchDNS('https://...') // when you may not actually request anything from this hostpreload("https://example.com/font.woff2", {as: "font"});//加载字体preload("https://example.com/style.css", {as: "style"});//预加载css文件preconnect('https://...') // when you will request something but aren't sure what}

这些会被转化为以下形式

  <head><!-- links/scripts are prioritized by their utility to early loading, not call order --><link rel="prefetch-dns" href="https://..."><link rel="preconnect" href="https://..."><link rel="preload" as="font" href="https://.../path/to/font.woff"><link rel="preload" as="style" href="https://.../path/to/stylesheet.css"><script async="" src="https://.../path/to/some/script.js"></script></head>

我们可以在渲染时和事件处理中进行预加载。
如果知道组件或其子组件将使用特定资源,那么在渲染组件时调用 preload。
在渲染时示例

import { preload } from 'react-dom';function AppRoot() {preload("https://example.com/font.woff2", {as: "font"});// ……
}

时间中

import { preload } from 'react-dom';function CallToAction() {const onClick = () => {preload("https://example.com/wizardStyles.css", {as: "style"});startWizard();}return (<button onClick={onClick}>Start Wizard</button>);
}
http://www.lryc.cn/news/345495.html

相关文章:

  • 【UE5】数字人基础
  • OSTEP Projects:KV
  • JAVA学习笔记(第三周)
  • linux 内核驱动 -- reboot -f 导致内核死机 而 reboot则不会引起问题
  • 【vue-echarts】 报错问题解决 “Error: Component series.pie not exists. Load it first.“
  • MySQL慢查询SQL优化
  • 【嵌入式DIY实例】-DDS信号生成器
  • java设计模式四 桥接模式
  • 《Python编程从入门到实践》day24
  • 【hackmyvm】 Animetronic靶机
  • [附源码]石器时代_恐龙宝贝内购版_三网H5手游_带GM工具
  • RS2255XN功能和参数介绍及PDF资料
  • 设计模式——外观模式(Facade)
  • 【linux软件基础知识】Linux 中的普通进程的调度机制
  • keil5软件安装教程(MDKv5.39)
  • 改变视觉创造力:图像合成中基于样式的生成架构的影响和创新
  • 【LAMMPS学习】八、基础知识(5.8)LAMMPS 中热化 Drude 振荡器教程
  • 基于SpringBoot的全国风景区WebGIS按省展示实践
  • 深入理解网络原理3----TCP核心特性介绍(上)【面试高频考点】
  • Java并发编程之锁的艺术:面试与实战指南(三)
  • Final Draft 12 for Mac:高效专业剧本创作软件
  • php字符串变量和常见的字符串函数
  • PPT基础
  • 初识JDBC
  • React 学习-5
  • 深入浅出TCP 与 UDP
  • Leetcode—387. 字符串中的第一个唯一字符【简单】
  • Blazor入门-调用js+例子
  • 暴力数据结构之栈与队列(队列详解)
  • 仿照JDK源码写一个ArrayList实现