React19学习-初体验

2024-05-11 1275阅读

升级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 (
    
name} onChange={(event) = setName(event.target.value)} /> handleSubmit} disabled={isPending} Update {error &&

{error}

}
); }

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

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

{error}

}
) }

效果展示

React19学习-初体验

表单提交状态+行为useActionState

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

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

示例

import {useActionState, useEffect} from "react";
function updateName(name:string):Promise{
    return new Promise((r)=>{
        setTimeout(()=>{
            if (!name)r("name不能为空")
            r(name)
        },2000)
    })
}
export default ()=>{
    const [state, submitAction, isPending] = useActionState(
        async (previousState:string, formData) => {
            const state = await updateName(formData.get("name"));
            // handle success
            return state;
        },
        "初始name值",
    );
    return (
        submitAction}
            
            isPending}Update
            {isPending && 
} {state && {color:"green"}}{state}} ); }

React19学习-初体验

获取父组件表单状态useFormStatus

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

子组件

import {useFormStatus} from "react-dom";
export default ()=>{
    const {pending} = useFormStatus();
    return pending} 提交表单
}

父组件部分代码展示

 submitAction}
            
            
            {isPending && 
} {state && {color:"green"}}{state}}

效果展示React19学习-初体验

乐观更新useOptimistic

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

子组件

import {useOptimistic} from "react";
interface Props{
    currentName:string
    onUpdateName:(name:string)=>void
}
function updateName(name:string):Promise{
    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 (
        submitAction}
            

Your name is(currentName):{color:"green"}}{currentName}

Your name is(optimisticName): {optimisticName}

Change Name: currentName !== optimisticName} /

提交 ); }

父组件

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

结果展示React19学习-初体验

其他

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 placeholder} ref={ref} /
}
ref} /

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

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

Context 不再需要

const ThemeContext = createContext('');
function App({children}) {
  return (
    
      {children}
    
  );  
}

支持在组件中编写Meta标签

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

function BlogPost({post}) {
  return (
    
      

{post.title}

{post.title} post.keywords} /

Eee equals em-see-squared...

); }

支持预加载资源

文档

在初始文档加载和客户端更新期间,告知浏览器可能需要尽早加载的资源可能会对页面性能产生巨大影响。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 eagerly
  preload('https://.../path/to/font.woff', { as: 'font' }) // preloads this font
  preload('https://.../path/to/stylesheet.css', { as: 'style' }) // preloads this stylesheet
  prefetchDNS('https://...') // when you may not actually request anything from this host
  preload("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
  
}

这些会被转化为以下形式

  
    
    
    
    
    
    
  

我们可以在渲染时和事件处理中进行预加载。

如果知道组件或其子组件将使用特定资源,那么在渲染组件时调用 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 (
    onClick}Start Wizard
  );
}
VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]