React

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > React > React并发机制

一文带你了解React中的并发机制

作者:纯爱掌门人

React 18.2.0 引入了一系列并发机制的新特性,旨在帮助各位开发者更好地控制和优化应用程序的性能和用户体验,下面我们就来看看如何利用这些新特性构建更高效、更响应式的应用程序吧

一、自动批处理

React 现在可以自动将多个状态更新操作批量处理,以减少不必要的渲染和提高性能。这意味着,当你在一个事件处理程序中连续调用多个状态更新函数时,React 会将它们合并为一次更新,从而减少渲染次数。

计数器

在下面这个案例中,当用户点击按钮时,handleClick 函数会连续调用三次 setCount。由于 React 的自动批处理,这三次更新会被合并为一次更新,从而减少渲染次数。

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    setCount(count + 1);
    setCount(count + 2);
    setCount(count + 3);
  };

  return (
    <div>
      <p>Count: {count}</p>
     <button onClick={handleClick}>Increment by 3</button>
    </div>
  );
}

二、异步渲染

React现在可以支持异步渲染,这意味着 React 可以在渲染过程中暂停和恢复,从而允许其他任务(如用户输入或动画)优先执行。这有助于提高应用程序的响应性和性能。

异步数据获取

在下面这个案例中,AsyncComponent 组件在挂载时会异步获取数据。由于 React 的异步渲染,当数据还未获取到时,组件会显示 "Loading...",而不会阻塞其他任务的执行。

import { useState, useEffect } from 'react';

function AsyncComponent() {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetchData().then((fetchedData) => {
      setData(fetchedData);
    });
  }, []);

  if (data === null) {
    return <p>Loading...</p>;
  }

  return <div>{data}</div>;
}

async function fetchData() {
  // 模拟异步数据获取
  await new Promise((resolve) => setTimeout(resolve, 1000));
  return 'Async data';
}

三、useDeferredValue:延迟值更新

useDeferredValue 是一个新的 Hook,它允许你在渲染过程中延迟某些值的更新,直到下一次渲染。这对于实现响应式 UI 和避免不必要的渲染非常有用。

输入框防抖

在下面这个示例中,当用户在输入框中输入文本时,useDeferredValue 会延迟更新 deferredText,直到 500 毫秒后的下一次渲染。这有助于提高应用程序的响应性和性能。

import { useState, useDeferredValue } from 'react';

function DebounceInput() {
  const [text, setText] = useState('');
  const deferredText = useDeferredValue(text, { timeoutMs: 500 });

  const handleChange = (e) => {
    setText(e.target.value);
  };

  return (
    <div>
     <input type="text" value={text} onChange={handleChange} />
      <p>Debounced value: {deferredText}</p>
    </div>
  );
}

四、useTransition:创建过渡状态

useTransition 是一个新的 Hook,它允许你在状态更新过程中创建一个过渡(transition),从而实现更细粒度的更新控制。你可以使用这个 Hook 来延迟某些状态更新,直到过渡完成。这对于实现更好的用户体验和性能优化非常有用。

加载状态与过渡效果

在下面这个示例中,当用户点击按钮时,handleClick 函数会使用 startTransition 创建一个过渡,并在过渡期间延迟更新 countisPending 变量表示过渡是否正在进行中,当过渡正在进行时,会显示 "Loading..."。

import { useState, useTransition } from 'react';

function TransitionExample() {
  const [count, setCount] = useState(0);
  const [isPending, startTransition] = useTransition();

  const handleClick = () => {
    startTransition(() => {
      setCount(count + 1);
    });
  };

  return (
    <div>
      <p>Count: {count}</p>
     <button onClick={handleClick}>Increment</button>
      {isPending && <p>Loading...</p>}
    </div>
  );
}

五、Suspense 配置优化

React新版本引入了新的 Suspense 配置选项,如 timeoutMs 和 fallbackAfterSuspense。这些选项允许你更精细地控制 Suspense 的行为,例如设置挂起时间和在挂起后显示备用内容。

分页加载与错误处理

在下面这个示例中,App 组件使用 Suspense 包裹了两个异步加载的页面组件 Page1 和 Page2。通过设置 timeoutMs 为 1000 毫秒,我们可以在 1 秒后显示 fallbackAfterSuspense 属性指定的备用内容 "Loading with suspense..."。同时,当 Page2 加载失败时,Suspense 会捕获错误并显示默认的错误边界内容

import { Suspense } from 'react';

function App() {
  return (
    <Suspense
      fallback={<div>Loading...</div>}
      timeoutMs={1000}
      fallbackAfterSuspense={<div>Loading with suspense...</div>}
    >
      <Page1 />
      <Page2 />
    </Suspense>
  );
}

function Page1() {
  // 模拟异步数据获取
  return new Promise((resolve) => setTimeout(() => resolve(<div>Page 1</div>), 2000));
}

function Page2() {
  // 模拟异步数据获取失败
  return new Promise((_, reject) => setTimeout(() => reject(new Error('Error loading Page 2')), 2000));
}

六、startTransition:手动创建过渡

startTransition 是一个新的函数,它允许你在状态更新过程中创建一个过渡(transition)。你可以使用这个函数来延迟某些状态更新,直到过渡完成。这对于实现更好的用户体验和性能优化非常有用。

动画与过渡的协同

在下面这个示例中,当用户点击按钮时,handleClick 函数会使用 startTransition 创建一个过渡,并在过渡期间平滑地移动盒子。通过结合 CSS 动画和 React 过渡,可以实现更自然、更流畅的交互体验。

import { useState, startTransition } from 'react';

function AnimationTransitionExample() {
  const [position, setPosition] = useState(0);

  const handleClick = () => {
    // 使用 startTransition 创建过渡
    startTransition(() => {
      setPosition(position + 100);
    });
  };

  return (
    <div style={{ position: 'relative' }}>
      <div
        style={{
          position: 'absolute',
          left: position,
          transition: 'left 0.5s ease-out',
        }}
      >
        Box
      </div>
     <button onClick={handleClick}>Move box</button>
    </div>
  );
}

七、useId 与 useSyncExternalStore:与外部数据源同步

这两个新的 Hooks 提供了更好的支持,以便在 React 组件和外部数据源之间同步数据。useId 用于生成唯一的 ID,而 useSyncExternalStore 用于在组件和外部数据源之间同步数据。

实时聊天应用

在下面这个示例中,ChatRoom 组件使用 useSyncExternalStore 从外部数据源(chatStore)获取聊天消息列表。当外部数据源的数据发生变化时,组件会自动重新渲染。同时,每个 ChatMessage 组件都使用 useId 生成了一个唯一的 ID,以便在 DOM 中正确引用它们。

import { useId, useSyncExternalStore } from 'react';

function ChatMessage({ message }) {
  const id = useId();
  return <div id={`message-${id}`}>{message}</div>;
}

function ChatRoom() {
  const messages = useSyncExternalStore(
    () => chatStore.subscribe,
    () => chatStore.getMessages()
  );

  return (
    <div>
      {messages.map((message) => (
        <ChatMessage key={message.id} message={message.text} />
      ))}
    </div>
  );
}

const chatStore = {
  messages: [],
  subscribers: new Set(),

  subscribe(callback) {
    this.subscribers.add(callback);
    return () => {
      this.subscribers.delete(callback);
    };
  },

  getMessages() {
    return this.messages;
  },

  addMessage(message) {
    this.messages.push(message);
    this.subscribers.forEach((callback) => callback());
  },
};

总结以及预测

React新版本的并发机制提供了一系列新特性,包括自动批处理、异步渲染、新的 Hooks 和 Suspense 配置等。这些特性旨在帮助开发者更好地控制和优化应用程序的性能和用户体验。通过这些新特性我看到了React在性能优化和用户体验方面的巨大潜力。

下面是掌门人对于React并发机制的一些预测,若是大家与我想法不一致,还请嘴下留情。

从长远来看,React的发展将更加注重性能、可维护性和开发者体验,React目前的发展趋势应该是将自身打造为一个全栈底层的基座,同时,随着物联网设备的普及,React也可能会拓展其在该领域的应用。

到此这篇关于一文带你了解React中的并发机制的文章就介绍到这了,更多相关React并发机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文