React 19 新特性!

179 阅读3分钟

1、useActionState 方便表单操作

import React, { useState } from 'react';

// 自定义 Hook:useActionState
function useActionState() {
  const [isLoading, setIsLoading] = useState(false);

  const startAction = () => setIsLoading(true);
  const endAction = () => setIsLoading(false);

  return [isLoading, startAction, endAction];
}

function ActionButton() {
  const [isLoading, startAction, endAction] = useActionState();

  const handleClick = async () => {
    startAction();
    // 模拟一个异步操作
    await new Promise((resolve) => setTimeout(resolve, 2000));
    endAction();
  };

  return (
    <div>
      <button onClick={handleClick} disabled={isLoading}>
        {isLoading ? '加载中...' : '点击执行操作'}
      </button>
    </div>
  );
}

export default ActionButton;

2、useFormStatus 帮助控制表单的整体状态

import React, { useState } from 'react';

// 自定义 Hook:useFormStatus
function useFormStatus() {
  const [isSubmitting, setIsSubmitting] = useState(false); // 表单是否正在提交
  const [isValid, setIsValid] = useState(true); // 表单是否有效
  const [errors, setErrors] = useState({}); // 存储错误信息

  const startSubmit = () => {
    setIsSubmitting(true); // 开始提交
  };

  const endSubmit = () => {
    setIsSubmitting(false); // 提交结束
  };

  const setFormErrors = (errorObj) => {
    setErrors(errorObj); // 设置错误信息
  };

  const setFormValid = (valid) => {
    setIsValid(valid); // 设置表单有效性
  };

  return { isSubmitting, isValid, errors, startSubmit, endSubmit, setFormErrors, setFormValid };
}

function MyForm() {
  const { isSubmitting, isValid, errors, startSubmit, endSubmit, setFormErrors, setFormValid } = useFormStatus();

  const handleSubmit = async (e) => {
    e.preventDefault();

    startSubmit();
    
    // 假设表单验证过程
    const formErrors = {};
    const formData = new FormData(e.target);

    if (!formData.get('username')) {
      formErrors.username = '用户名不能为空';
    }
    
    if (!formData.get('password')) {
      formErrors.password = '密码不能为空';
    }

    if (Object.keys(formErrors).length > 0) {
      setFormErrors(formErrors);
      setFormValid(false);
      endSubmit();
      return;
    }

    // 模拟一个异步提交操作
    await new Promise((resolve) => setTimeout(resolve, 2000));

    endSubmit();
    alert('表单提交成功');
  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="username">用户名:</label>
        <input type="text" id="username" name="username" />
        {errors.username && <p style={{ color: 'red' }}>{errors.username}</p>}
      </div>

      <div>
        <label htmlFor="password">密码:</label>
        <input type="password" id="password" name="password" />
        {errors.password && <p style={{ color: 'red' }}>{errors.password}</p>}
      </div>

      <div>
        <button type="submit" disabled={isSubmitting || !isValid}>
          {isSubmitting ? '提交中...' : '提交'}
        </button>
      </div>
    </form>
  );
}

export default MyForm;

3、useOptimistic 乐观更新

用户触发某些操作时,立即在界面上反映结果,而无需等待服务器响应。如果操作失败,再回滚到之前的状态。

import React, { useState } from 'react';

// 假设这是一个异步 API 请求函数
const mockApiRequest = (newLikes) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() > 0.2 ? resolve(newLikes) : reject(new Error('点赞失败'));
    }, 1000);
  });
};

function useOptimistic(initialState) {
  const [state, setState] = useState(initialState);
  const [backup, setBackup] = useState(initialState);

  const optimisticUpdate = (updater, rollback) => {
    setBackup(state); // 保存当前状态以便回滚
    const updatedState = updater(state);
    setState(updatedState);

    return async (action) => {
      try {
        await action(updatedState); // 执行实际操作
      } catch (error) {
        setState(rollback(backup)); // 操作失败,回滚状态
        throw error;
      }
    };
  };

  return [state, optimisticUpdate];
}

function LikeButton() {
  const [likes, optimisticUpdate] = useOptimistic(0);

  const handleLike = async () => {
    const executeAction = optimisticUpdate(
      (currentLikes) => currentLikes + 1,
      (previousLikes) => previousLikes
    );

    try {
      await executeAction(() => mockApiRequest(likes + 1));
      console.log('点赞成功');
    } catch (error) {
      console.error(error.message);
    }
  };

  return (
    <button onClick={handleLike}>
      点赞 {likes}
    </button>
  );
}

export default LikeButton;

4、支持的 metadata tags

import React from 'react';
import { MetadataProvider, Title, Meta, Link } from '@react/metadata';

function HomePage() {
  return (
    <>
      <Title>首页 - 我的网站</Title>
      <Meta name="description" content="这是我的网站首页,包含关于 React 19 的新特性介绍。" />
      <Meta name="keywords" content="React 19, Metadata Tags, 新特性" />
      <Link rel="canonical" href="https://www.mywebsite.com/" />
      <h1>欢迎来到我的网站</h1>
      <p>探索 React 19 中的新特性!</p>
    </>
  );
}

function AboutPage() {
  return (
    <>
      <Title>关于我们 - 我的网站</Title>
      <Meta name="description" content="了解更多关于我们团队的信息。" />
      <Meta name="keywords" content="关于我们, React 19, Metadata Tags" />
      <Link rel="canonical" href="https://www.mywebsite.com/about" />
      <h1>关于我们</h1>
      <p>我们是一支专注于现代 Web 开发的团队。</p>
    </>
  );
}

function App() {
  return (
    <MetadataProvider>
      {/* 模拟路由切换 */}
      <HomePage />
      {/* 替换为 <AboutPage /> 可观察元数据的变化 */}
    </MetadataProvider>
  );
}

export default App;

5、资源加载改进

例子:首屏预加载

import React from 'react';

function HomePage() {
  return (
    <div>
      <h1>Welcome to React 19!</h1>
      <img
        src="hero.jpg"
        alt="Hero"
        width="800"
        height="400"
        loading="eager"
      />
    </div>
  );
}

export default HomePage;

6、Web 组件支持

示例:使用 Web Components 与 React 集成

定义一个 Web Component
// custom-button.js
class CustomButton extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({ mode: 'open' });

    const button = document.createElement('button');
    button.textContent = this.getAttribute('label') || 'Click me';

    button.addEventListener('click', () => {
      const event = new CustomEvent('onCustomClick', {
        detail: { message: 'Button clicked!' },
      });
      this.dispatchEvent(event);
    });

    shadow.appendChild(button);
  }
}

customElements.define('custom-button', CustomButton);

在 React 中使用 Web Component

import React from 'react';
import './custom-button.js'; // 引入 Web Component 定义

function App() {
  const handleCustomClick = (event) => {
    alert(event.detail.message);
  };

  return (
    <div>
      <h1>React 19 Web Components Support</h1>
      <custom-button
        label="Click Me"
        onCustomClick={handleCustomClick}
      ></custom-button>
    </div>
  );
}

export default App;