πŸš€ НовыС возмоТности React 19: ΠΊΠΎΠ½Π΅Ρ† эры ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½Ρ‹Ρ… Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³ΠΎΠ²

Новый компилятор React 19 ΠΎΠ±Π΅Ρ‰Π°Π΅Ρ‚ сущСствСнноС ΠΏΠΎΠ²Ρ‹ΡˆΠ΅Π½ΠΈΠ΅ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ, Ρ‡Ρ‚ΠΎ станСт настоящим ΠΏΡ€ΠΎΡ€Ρ‹Π²ΠΎΠΌ для Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΎΠ². Но это лишь Π²Π΅Ρ€Ρ…ΡƒΡˆΠΊΠ° айсбСрга. Π’ этой ΡΡ‚Π°Ρ‚ΡŒΠ΅ ΠΌΡ‹ Π½Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ разбСрСмся, ΠΊΠ°ΠΊ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ компилятор, Π½ΠΎ ΠΈ погрузимся Π² ΠΌΠΈΡ€ Π΄Ρ€ΡƒΠ³ΠΈΡ… Π½ΠΎΠ²Π΅ΠΉΡˆΠΈΡ… возмоТностСй React 19.

ΠŸΡ€ΠΈΠ²Π΅Ρ‚, Π΄Ρ€ΡƒΠ·ΡŒΡ! Π― ΠšΠΈΡ€ΠΈΠ»Π» ΠœΡ‹Π»ΡŒΠ½ΠΈΠΊΠΎΠ², Ρ„Ρ€ΠΎΠ½Ρ‚Π΅Π½Π΄-Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Π² ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ Usetech. БСгодня Ρ…ΠΎΡ‡Ρƒ ΠΏΠΎΠ΄Π΅Π»ΠΈΡ‚ΡŒΡΡ ΠΎ Π½ΠΎΠ²Π΅ΠΉΡˆΠΈΡ… функциях Π² React 19. Π”Π°Π²Π°ΠΉΡ‚Π΅ вмСстС ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΠΌ ΠΈΡ… Π² ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ΅, Ρ€Π°Π·Π±Π΅Ρ€Π΅ΠΌ Π½ΠΎΠ²ΡˆΠ΅ΡΡ‚Π²Π° ΠΈ возмоТности Π½Π° ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°Ρ…, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠ·Π½Π°Ρ‚ΡŒ, ΠΊΠ°ΠΊ ΠΎΠ½ΠΈ ΠΌΠΎΠ³ΡƒΡ‚ ΡƒΠ»ΡƒΡ‡ΡˆΠΈΡ‚ΡŒ Π½Π°ΡˆΡƒ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ! Π“ΠΎΡ‚ΠΎΠ²Ρ‹ ΠΊ ΠΏΠΎΠ³Ρ€ΡƒΠΆΠ΅Π½ΠΈΡŽ?

ΠšΠΎΠΌΠΏΠΈΠ»ΡΡ‚ΠΎΡ€ React

Π­Ρ‚ΠΎ новСйшСС Π΄ΠΎΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ ΠΊ React β€” компилятор, Π·Π°ΠΌΠ΅Π½ΡΡŽΡ‰ΠΈΠΉ транспилятор, примСняСтся Π² React 19. Π’ React 18 ΠΈ Π½ΠΈΠΆΠ΅ использовался транспилятор, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΏΡ€ΠΈ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΈ состояния пСрСрисовывал вСсь ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚. Π’ ΠΎΡ‚Π»ΠΈΡ‡ΠΈΠ΅ ΠΎΡ‚ Π½Π΅Π³ΠΎ, компилятор Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ ΠΌΠ΅ΠΌΠΎΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ ΠΊΠΎΠ΄, устраняя Π½Π΅Π½ΡƒΠΆΠ½Ρ‹ΠΉ ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½Ρ‹ΠΉ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³ ΠΈ ΡƒΠ»ΡƒΡ‡ΡˆΠ°Ρ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ React. Π”Π°Π²Π°ΠΉΡ‚Π΅ запустим ΠΊΠΎΠ΄ Π² ΠΎΠ±Π΅ΠΈΡ… вСрсиях ΠΈ ΠΈΠ·ΡƒΡ‡ΠΈΠΌ Ρ€Π°Π·Π½ΠΈΡ†Ρƒ Π² ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² ΠΏΡ€ΠΈ ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎΠΉ Π²ΠΈΠ·ΡƒΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€

// Component to measure and log the time taken to render the header
function TimeToRender() {
  // Record the start time when the component begins rendering
  const startTime = performance.now();

  useEffect(() => {
    // Record the end time when the component has rendered
    const endTime = performance.now();
    // Log the time taken to render the component
    console.log(`CustomHeader render time: ${endTime - startTime}ms`);
 }, []); // Empty dependency array ensures this effect runs only once after the initial render

  return (
    <header>
      <h1>Counter App</h1>
    </header>
 );
}

// Main component of the Counter App
function CounterApp() {
  // State hook to manage the count value
  const [count, setCount] = useState(0);

  return (
    <>
      {/* Render the TimeToRender component */}
      <TimeToRender />
      <div>
        {/* Display the current count */}
        <p>{count}</p>
        {/* Button to increase the count */}
        <button onClick={() => setCount(count + 1)}>Increase</button>
        {/* Button to decrease the count */}
        <button onClick={() => setCount(count - 1)}>Decrease</button>
      </div>
    </>
 );
}

// Export the CounterApp component as the default export
export default CounterApp;

ΠŸΡ€Π΅Π΄ΡΡ‚Π°Π²Π»Π΅Π½Π½Ρ‹ΠΉ Π²Ρ‹ΡˆΠ΅ ΠΊΠΎΠ΄ прСдставляСт собой ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅-счСтчик, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ ΡƒΠ²Π΅Π»ΠΈΡ‡ΠΈΠ²Π°Π΅Ρ‚ ΠΈ ΡƒΠΌΠ΅Π½ΡŒΡˆΠ°Π΅Ρ‚ счСтчик ΠΏΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ ΠΊΠ½ΠΎΠΏΠΊΠΈ. Π’ Π½Π΅ΠΌ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½Π° функция TimeToRender, которая замСряСт врСмя, Ρ‚Ρ€Π΅Π±ΡƒΠ΅ΠΌΠΎΠ΅ для Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π° ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° ΠΏΡ€ΠΈ ΠΊΠ°ΠΆΠ΄ΠΎΠΌ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΈ.

На ΠΈΠ»Π»ΡŽΡΡ‚Ρ€Π°Ρ†ΠΈΠΈ Π½ΠΈΠΆΠ΅ ΠΏΠΎΠΊΠ°Π·Π°Π½ процСсс Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π° ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° Π² компиляторС, Π° Ρ‚Π°ΠΊΠΆΠ΅ врСмя, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΠ΅ для Π΅Π³ΠΎ ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎΠ³ΠΎ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π°.

ΠŸΡ€ΠΎΡ†Π΅ΡΡ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π° ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° Π² компиляторС, Π° Ρ‚Π°ΠΊΠΆΠ΅ врСмя, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΠ΅ для Π΅Π³ΠΎ ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎΠ³ΠΎ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π°

На ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΈ Π½ΠΈΠΆΠ΅ ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ врСмя, Ρ‚Ρ€Π΅Π±ΡƒΠ΅ΠΌΠΎΠ΅ для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎΠ³ΠΎ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π° всСго ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° ΠΏΡ€ΠΈ использовании транспилятора.

ВрСмя, Ρ‚Ρ€Π΅Π±ΡƒΠ΅ΠΌΠΎΠ΅ для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎΠ³ΠΎ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π° всСго ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° ΠΏΡ€ΠΈ использовании транспилятора

На прСдставлСнном ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΈ Π²Ρ‹ΡˆΠ΅ ΠΌΡ‹ Π²ΠΈΠ΄ΠΈΠΌ, Ρ‡Ρ‚ΠΎ транспилятор выполняСт нСсколько ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½Ρ‹Ρ… Ρ€Π΅Π½Π΄Π΅Ρ€ΠΎΠ², ΠΏΡ€ΠΈ этом врСмя ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΏΠΎΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π³ΠΎ Ρ€Π΅Π½Π΄Π΅Ρ€Π° сокращаСтся послС ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ Ρ‰Π΅Π»Ρ‡ΠΊΠ°, Π² Ρ‚ΠΎ врСмя ΠΊΠ°ΠΊ компилятор выполняСт Ρ€Π΅Π½Π΄Π΅Ρ€ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π·.

Π Π°Π½Π΅Π΅ ΠΌΡ‹ использовали Ρ…ΡƒΠΊΠΈ memo, useMemo() ΠΈ useCallback() для достиТСния ΠΏΠΎΠ΄ΠΎΠ±Π½ΠΎΠ³ΠΎ эффСкта, Ρ‡Ρ‚ΠΎ Π΄Π΅Π»Π°Π΅Ρ‚ эти Ρ…ΡƒΠΊΠΈ ΡƒΡΡ‚Π°Ρ€Π΅Π²ΡˆΠΈΠΌΠΈ. Новый ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ позволяСт Π½Π°ΠΌ ΠΏΠΈΡΠ°Ρ‚ΡŒ Π±ΠΎΠ»Π΅Π΅ чистый ΠΈ ΠΊΠΎΠΌΠΏΠ°ΠΊΡ‚Π½Ρ‹ΠΉ ΠΊΠΎΠ΄.

НовыС Hooks

Π₯ΡƒΠΊΠΈ β€” это ΠΎΠ΄Π½Π° ΠΈΠ· Π½Π°ΠΈΠ±ΠΎΠ»Π΅Π΅ популярных особСнностСй React. Они ΠΎΠ±Π΅ΡΠΏΠ΅Ρ‡ΠΈΠ²Π°ΡŽΡ‚ ΡƒΠ΄ΠΎΠ±Π½ΠΎΠ΅ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ состояниСм ΠΈ ΠΆΠΈΠ·Π½Π΅Π½Π½Ρ‹ΠΌ Ρ†ΠΈΠΊΠ»ΠΎΠΌ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ². Π’ React ΡƒΠΆΠ΅ встроСны Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Ρ…ΡƒΠΊΠΈ, Π° Ρ‚Π°ΠΊΠΆΠ΅ прСдоставляСтся Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ создания собствСнных ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΡ… Ρ…ΡƒΠΊΠΎΠ².

Π’ React 19 Π±Ρ‹Π»ΠΎ Π²Π²Π΅Π΄Π΅Π½ΠΎ Ρ‡Π΅Ρ‚Ρ‹Ρ€Π΅ Π½ΠΎΠ²Ρ‹Ρ… Ρ…ΡƒΠΊΠ°:

  1. useTransition
  2. useActionState
  3. useFormStatus
  4. useOptimistic

useTransition

React 19 Π²Π½Π΅Π΄Ρ€ΠΈΠ» ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΡƒ использования async Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ Π² ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄Π°Ρ… для управлСния измСнСниями состояния, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΠΎΠ³ΡƒΡ‚ ΠΏΠΎΠ²Π»Π΅Ρ‡ΡŒ измСнСния ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ интСрфСйса. БущСствуСт Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ…ΡƒΠΊ useTransition для обновлСния статуса состояния ΠΈ автоматичСского отобраТСния процСсса оТидания.

Π­Ρ‚ΠΎ Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΡƒΠ΅Ρ‚ ΠΏΠ»Π°Π²Π½ΡƒΡŽ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΉ ΠΏΡ€ΠΈ ΠΈΠ½ΠΈΡ†ΠΈΠ°Ρ†ΠΈΠΈ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΌ. ΠšΡ€ΠΎΠΌΠ΅ Ρ‚ΠΎΠ³ΠΎ, интСрфСйс Π±ΡƒΠ΄Π΅Ρ‚ Ρ‚ΠΎΡ‡Π½ΠΎ ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Ρ‚ΡŒ Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π΅ состояниС асинхронной Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ. Π”Π°Π²Π°ΠΉΡ‚Π΅ посмотрим Π½Π° ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΊΠΎΠ΄Π°.

ΠŸΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½Ρ‹ΠΉ Π½ΠΈΠΆΠ΅ ΠΊΠΎΠ΄ прСдставляСт собой ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ добавляСт Π±ΡƒΠΊΠ²Ρ‹ Π°Π»Ρ„Π°Π²ΠΈΡ‚Π° Π² список. ΠŸΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ ΠΊΠ½ΠΎΠΏΠΊΠΈ "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ" происходит ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΠ΅ 4 сСкунды ΠΏΠ΅Ρ€Π΅Π΄ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ΠΌ Π½ΠΎΠ²ΠΎΠΉ Π±ΡƒΠΊΠ²Ρ‹ Π² список. ΠœΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ автоматичСски ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ состояниСм оТидания с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ startTransition().

import React, { useState, useTransition } from "react";

// Function to create a delay for a given number of milliseconds
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

// Asynchronous function to add an alphabet to the list after a delay
async function addAlphabetToList(alphabet) {
  await delay(4000);
  return null;
}

// Component to add an alphabet to a list
function AlphabetAdder() {
  const [alphabet, setAlphabet] = useState("");
  const [error, setError] = useState(null);
  // State and function for transition
  const [isPending, startTransition] = useTransition();
  const [alphabetList, setAlphabetList] = useState([]); // State to store the list of alphabets

  // Function to handle adding an alphabet to the list
  const handleAddAlphabet = async () => {
    startTransition(async () => {
      const error = await addAlphabetToList(alphabet); // Add alphabet to the list with delay
      if (error) {
        setError(error);
 } else {
        setAlphabetList([...alphabetList, alphabet]);
 }
 });
 };

  // Log the pending state
  console.log("Pending:", isPending);

  return <></>;
}

На ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΈ Π½ΠΈΠΆΠ΅ ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ, Ρ‡Ρ‚ΠΎ состояниС оТидания остаСтся Ρ€Π°Π²Π½Ρ‹ΠΌ true Π΄ΠΎ Ρ‚ΠΎΠ³ΠΎ ΠΌΠΎΠΌΠ΅Π½Ρ‚Π°, ΠΏΠΎΠΊΠ° Π±ΡƒΠΊΠ²Π° Π°Π»Ρ„Π°Π²ΠΈΡ‚Π° Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½Π° Π² список Ρ‡Π΅Ρ€Π΅Π· 4 сСкунды.

БостояниС оТидания остаСтся Ρ€Π°Π²Π½Ρ‹ΠΌ true Π΄ΠΎ Ρ‚ΠΎΠ³ΠΎ ΠΌΠΎΠΌΠ΅Π½Ρ‚Π°, ΠΏΠΎΠΊΠ° Π±ΡƒΠΊΠ²Π° Π°Π»Ρ„Π°Π²ΠΈΡ‚Π° Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½Π° Π² список Ρ‡Π΅Ρ€Π΅Π· 4 сСкунды

Π­Ρ‚ΠΎ происходит Π² ΠΎΡ‚Π»ΠΈΡ‡ΠΈΠ΅ ΠΎΡ‚ ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΡ… вСрсий, Π³Π΄Π΅ Π½Π°ΠΌ ΠΏΡ€ΠΈΡ…ΠΎΠ΄ΠΈΠ»ΠΎΡΡŒ Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ состояниСм оТидания, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ setIsPendingding для установки состояния Π² Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ true ΠΈΠ»ΠΈ false.

import React, { useState } from "react";

// Function to create a delay
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

// Async function to simulate adding an alphabet to a list after a delay
async function addAlphabetToList(alphabet) {
  await delay(4000);
  return null;
}

function AlphabetAdder() {
  const [alphabet, setAlphabet] = useState("");
  const [error, setError] = useState(null);
  // State to manage the pending state
  const [isPending, setIsPending] = useState(false);
  const [alphabetList, setAlphabetList] = useState([]);

  // Function to handle adding the alphabet
  const handleAddAlphabet = async () => {
    setIsPending(true);
    // Add the alphabet to the list after the delay
    const error = await addAlphabetToList(alphabet);
    if (error) {
      setError(error);
 } else {
      setAlphabetList([...alphabetList, alphabet]);
 }
    setIsPending(false);
 };

  // Log the pending state
  console.log("Pending:", isPending);

  return <></>;
}
export default AlphabetAdder;

useActionState

Π₯ΡƒΠΊ useActionState примСняСтся для управлСния измСнСниями состояния Π² ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠΌ интСрфСйсС, Π°Π½Π°Π»ΠΎΠ³ΠΈΡ‡Π½ΠΎ Ρ…ΡƒΠΊΡƒ useTransition. ΠžΡ‚Π»ΠΈΡ‡ΠΈΠ΅ ΠΌΠ΅ΠΆΠ΄Ρƒ Π½ΠΈΠΌΠΈ Π·Π°ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ useActionState позволяСт ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ состояния error, action ΠΈ pending Π² ΠΎΠ΄Π½ΠΎΠΉ строкС ΠΊΠΎΠ΄Π°, вмСсто Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… строк, ΠΊΠ°ΠΊ ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ Π²Ρ‹ΡˆΠ΅. ΠšΡ€ΠΎΠΌΠ΅ Ρ‚ΠΎΠ³ΠΎ, Ρ…ΡƒΠΊ useTransition ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ состояниС оТидания.

ΠŸΡƒΡ‚Π΅ΠΌ использования Ρ…ΡƒΠΊΠ° useActionState ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠ΅Ρ€Π΅ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΠΉ ΠΊΠΎΠ΄ Π±ΠΎΠ»Π΅Π΅ ΠΊΠΎΠΌΠΏΠ°ΠΊΡ‚Π½ΠΎ, Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Ρ‚ ΠΊ ΡƒΠΌΠ΅Π½ΡŒΡˆΠ΅Π½ΠΈΡŽ количСства строк ΠΊΠΎΠ΄Π°.

const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

async function addAlphabetToList(name) {
  await delay(4000);
  return null;
}

function AlphabetAdder() {
  const [error, submitAction, isPending] = useActionState(
    async (previousState, formData) => {
      const error = await addAlphabetToList(formData.get("name"));
      if (error) {
        return error;
 }

      return null;
 },
    null,
 );

  console.log("Pending:", isPending);
  return <></>;
}

Π’ прСдставлСнном Π²Ρ‹ΡˆΠ΅ ΠΊΠΎΠ΄Π΅ Ρ…ΡƒΠΊ useActionState ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для автоматичСской ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ состояний error, submitAction ΠΈ isPending Π±Π΅Π· явного опрСдСлСния Ρ‡Π΅Ρ€Π΅Π· useState ΠΈΠ»ΠΈ useTransition для состояний, ΠΎΠΆΠΈΠ΄Π°ΡŽΡ‰ΠΈΡ… обновлСния, ΠΊΠ°ΠΊ ΠΌΡ‹ Π΄Π΅Π»Π°Π»ΠΈ Ρ€Π°Π½Π΅Π΅.

useFormStatus

Π₯ΡƒΠΊ useFormStatus прСдоставляСт доступ ΠΊ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ ΠΎ состоянии ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½Π½ΠΎΠΉ Ρ„ΠΎΡ€ΠΌΡ‹. Π‘ Π΅Π³ΠΎ ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ доступ ΠΊ ΡΠΎΡΡ‚ΠΎΡΠ½ΠΈΡŽ Ρ„ΠΎΡ€ΠΌΡ‹ ΠΈ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ, находится Π»ΠΈ ΠΎΠ½Π° Π² Ρ€Π΅ΠΆΠΈΠΌΠ΅ оТидания ΠΈΠ»ΠΈ Π½Π΅Ρ‚.

НиТС ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΊΠΎΠ΄Π°, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ использован Ρ…ΡƒΠΊ useFormStatus для доступа ΠΊ ΡΠΎΡΡ‚ΠΎΡΠ½ΠΈΡŽ оТидания Ρ„ΠΎΡ€ΠΌΡ‹.

function FormStatusButton() {
  const { isPending } = useFormStatus();
  return (
    <div>
      <button type="submit" disabled={isPending}>
        {isPending ? "Adding..." : "Add"}
      </button>
    </div>
 );
}

Π Π°Π½Π΅Π΅ для доступа ΠΊ ΡΠΎΡΡ‚ΠΎΡΠ½ΠΈΡŽ оТидания ΠΌΡ‹ ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Π»ΠΈ это состояниС ΠΊΠ°ΠΊ пропс. Π’ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½ΠΎΠΌ Π½ΠΈΠΆΠ΅ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ ΠΊΠΎΠ΄Π° ΠΌΡ‹ ΠΏΠ΅Ρ€Π΅Π΄Π°Π»ΠΈ состояниС isPending ΠΊΠ°ΠΊ пропс Π² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ CustomButton, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΠΌΠ΅Ρ‚ΡŒ ΠΊ Π½Π΅ΠΌΡƒ доступ Π² ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Π΅ return.

function CustomButton({ isPending }) {
  return (
    <div>
      <button type="submit" disabled={isPending}>
        {isPending ? "Adding..." : "Add"}
      </button>
    </div>
 );
}

useOptimistic

Π­Ρ‚ΠΎΡ‚ Ρ…ΡƒΠΊ позволяСт Π½Π°ΠΌ ΠΎΠ±Π½ΠΎΠ²Π»ΡΡ‚ΡŒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ интСрфСйс Π½Π΅ΠΌΠ΅Π΄Π»Π΅Π½Π½ΠΎ ΠΏΡ€ΠΈ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΈ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½ΠΎΠ³ΠΎ состояния, Π΄Π°ΠΆΠ΅ Π±Π΅Π· оТидания Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ асинхронного дСйствия. НапримСр, Π² Ρ‡Π°Ρ‚-прилоТСниях, ΠΊΠΎΠ³Π΄Π° сообщСниС отправляСтся, ΠΎΠ½ΠΎ ΠΌΠ³Π½ΠΎΠ²Π΅Π½Π½ΠΎ отобраТаСтся Π² интСрфСйсС Π΄ΠΎ Π΅Π³ΠΎ фактичСской ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚Π΅Π»ΡŽ. Часто Π΄ΠΎΠ±Π°Π²Π»ΡΡŽΡ‚ΡΡ ΠΈΠ½Π΄ΠΈΠΊΠ°Ρ‚ΠΎΡ€Ρ‹, Ρ‚Π°ΠΊΠΈΠ΅ ΠΊΠ°ΠΊ Π³Π°Π»ΠΎΡ‡ΠΊΠΈ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ, ΠΊΠΎΠ³Π΄Π° сообщСниС Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ доставлСно.

Π’ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½ΠΎΠΌ Π½ΠΈΠΆΠ΅ ΠΊΠΎΠ΄Π΅ ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ для списка Π·Π°Π΄Π°Ρ‡, Π³Π΄Π΅ ΠΏΡ€ΠΈ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠΈ Π½ΠΎΠ²ΠΎΠΉ Π·Π°Π΄Π°Ρ‡ΠΈ ΠΎΠ½Π° ΠΏΡ€ΠΎΡ…ΠΎΠ΄ΠΈΡ‚ Ρ‡Π΅Ρ€Π΅Π· Π°ΡΠΈΠ½Ρ…Ρ€ΠΎΠ½Π½ΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ ΠΈ Π·Π°Ρ‚Π΅ΠΌ обновляСтся Π² ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠΌ интСрфСйсС Ρ‡Π΅Ρ€Π΅Π· 4 сСкунды. ΠœΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Ρ…ΡƒΠΊ useOptimistic для ΠΌΠ³Π½ΠΎΠ²Π΅Π½Π½ΠΎΠ³ΠΎ отобраТСния Π΄ΠΎΠ±Π°Π²Π»Π΅Π½Π½ΠΎΠΉ Π·Π°Π΄Π°Ρ‡ΠΈ Π² интСрфСйсС Π΄ΠΎ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ 4-сСкундного Π²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠ³ΠΎ ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π»Π°.

function App({ initialTasks }) {
  // State to hold the tasks
  const [tasks, setTasks] = useState(initialTasks);
  // Optimistic UI state for tasks
  const [optimisticTask, addOptimisticTasks] = useOptimistic(tasks);

  const inputRef = useRef(null);

  // Handle form submission
  async function handleSubmit(e) {
    if (inputRef.current == null) return;

    // Create an optimistic task
    const optimisticTask = {
      id: crypto.randomUUID(),
      title: inputRef.current.value,
 };

    // Add the optimistic task to the state
    addOptimisticTasks((prev) => [...prev, optimisticTask]);

    // Create a new task (simulating server creation)
    const newTask = await createTask(inputRef.current.value);
    // Add the new task to the state
    setTasks((prev) => [...prev, newTask]);
 }

  return (
    <>
      <form action={handleSubmit}>
        <label>Add New Task</label>
        <br />
        <input ref={inputRef} required />
        <br />
        <button>Create Task</button>
      </form>
      <ul>
        {/* Render the list of optimistic tasks */}
        {optimisticTask.map((task) => (
          <li key={task.id}>{task.title}</li>
 ))}
      </ul>
    </>
 );
}

// Function that simulates creating a task on the server
function createTask(title) {
  return delay(
 { id: crypto.randomUUID(), title: `${title} - in the server` },
    4000,
 );
}

// Function to create a delay
function delay(value, duration) {
  return new Promise((resolve) => {
    setTimeout(() => resolve(value), duration);
 });
}

export default App;

На Π΄Π°Π½Π½ΠΎΠΌ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΈ дСмонстрируСтся ΠΌΠ³Π½ΠΎΠ²Π΅Π½Π½ΠΎΠ΅ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ интСрфСйса. Π§Π΅Ρ€Π΅Π· 4 сСкунды отобраТаСмая Π·Π°Π΄Π°Ρ‡Π° замСняСтся Π½Π° Π°ΠΊΡ‚ΡƒΠ°Π»ΡŒΠ½ΡƒΡŽ Π·Π°Π΄Π°Ρ‡Ρƒ с сСрвСра.

МгновСнноС ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ интСрфСйса. Π§Π΅Ρ€Π΅Π· 4 сСкунды отобраТаСмая Π·Π°Π΄Π°Ρ‡Π° замСняСтся Π½Π° Π°ΠΊΡ‚ΡƒΠ°Π»ΡŒΠ½ΡƒΡŽ Π·Π°Π΄Π°Ρ‡Ρƒ с сСрвСра

Π Π°Π½Π΅Π΅ для Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ этой Π·Π°Π΄Π°Ρ‡ΠΈ ΠΌΡ‹ использовали Ρ…ΡƒΠΊ useState для управлСния оптимистичным ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ΠΌ Π·Π°Π΄Π°Ρ‡ ΠΈ ΠΈΡ… дальнСйшСго обновлСния с фактичСскими Π΄Π°Π½Π½Ρ‹ΠΌΠΈ.

const [tasks, setTasks] = useState(initialTasks);
// Setting optimistic tasks using the useState hook
const [optimisticTasks, setOptimisticTasks] = useState(initialTasks);

const inputRef = useRef(null);

async function handleSubmit(e) {
  e.preventDefault(); // Prevent default form submission

  if (inputRef.current == null) return;

  const optimisticTask = {
    id: crypto.randomUUID(),
    title: inputRef.current.value,
 };

  // Add the optimistic task immediately
  setOptimisticTasks((prev) => [...prev, optimisticTask]);

  // Create the actual task with a delay
  const newTask = await createTask(inputRef.current.value);
  setTasks((prev) => [...prev, newTask]);
  setOptimisticTasks((prev) =>
    prev.map((task) => (task.id === optimisticTask.id ? newTask : task)),
 );
}

Π’Ρ‹ΡˆΠ΅ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Ρ…ΡƒΠΊ useState для добавлСния оптимистичных ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΉ интСрфСйса Π² состояниС optimisticTasks, Π° Ρ‚Π°ΠΊΠΆΠ΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ-сСттСр setOptimisticTasks для обновлСния этого состояния.

πŸ‘¨β€πŸ’»πŸŽ¨ Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° Ρ„Ρ€ΠΎΠ½Ρ‚Π΅Π½Π΄Π΅Ρ€Π°
Π‘ΠΎΠ»ΡŒΡˆΠ΅ ΠΏΠΎΠ»Π΅Π·Π½Ρ‹Ρ… ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»ΠΎΠ² Π²Ρ‹ Π½Π°ΠΉΠ΄Π΅Ρ‚Π΅ Π½Π° нашСм Ρ‚Π΅Π»Π΅Π³Ρ€Π°ΠΌ-ΠΊΠ°Π½Π°Π»Π΅ Β«Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° Ρ„Ρ€ΠΎΠ½Ρ‚Π΅Π½Π΄Π΅Ρ€Π°Β»

Новый API

API use позволяСт ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ промисы ΠΈ async-await. Он ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ промис, Π° Π½Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, ΠΈ обновляСт ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ интСрфСйс послС Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ промиса. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π²Ρ‹Π·Ρ‹Π²Π°Ρ‚ΡŒ этот API Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΠ² if ΠΈ Ρ†ΠΈΠΊΠ»ΠΎΠ².

Π’ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½ΠΎΠΌ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ ΠΊΠΎΠ΄Π° содСрТатся Π΄Π²Π΅ асинхронныС Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΈΠΌΠΈΡ‚ΠΈΡ€ΡƒΡŽΡ‚ Π·Π°Π΄Π΅Ρ€ΠΆΠΊΡƒ ΠΏΡ€ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠΈ Π΄Π°Π½Π½Ρ‹Ρ…, ΠΊΠ°ΠΊ это ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ происходит ΠΏΡ€ΠΈ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠ΅ запросов Π½Π° сСрвСр. ΠŸΠ΅Ρ€Π²Π°Ρ функция Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ список Π°Π²Ρ‚ΠΎΡ€ΠΎΠ² послС Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠΈ Π² 4 сСкунды, Π° вторая – список Π±Π»ΠΎΠ³ΠΎΠ² послС Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠΈ Π² 2 сСкунды. Π—Π°Ρ‚Π΅ΠΌ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ интСрфСйс обновляСтся этими значСниями.

import { use, Suspense } from "react";

// Create a delay
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

// Async function that fetches the list of blogs after the delay
const getBlogs = async () => {
  await delay(4000);
  return ["OpenReplay", "Devto", "Medium"];
};

// Async function that fetches the list of authors after a delay
const getAuthors = async () => {
  await delay(2000);
  return {
    isFetchUsers: true,
    authors: ["Mary Chidera", "Ugorji Marydera", "Ken Erics"],
 };
};

// Component to retrieve and display authors and blogs
function RetrieveAuthors({ authorsPromise, blogsPromise }) {
  // Use the authorsPromise to get the authors' data
  const { isFetchUsers, authors } = use(authorsPromise);

  console.log("Authors Promise Done: ", authors);

  let blogs;
  // If users are fetched, use the blogsPromise to get the blogs data
  if (isFetchUsers) blogs = use(blogsPromise);

  console.log("Blogs Promise is done :", blogs);

  return (
    <>
      <div>
        <h2>Authors</h2>
        <div>
          {/* Map over the authors array and display each author */}
          {authors.map((author, idx) => (
            <p key={idx}>{author}</p>
 ))}
        </div>
      </div>
      {blogs && (
        <div>
          <h2>Top Blogs</h2>
          <div>
            {/* Map over the blogs array and display each blog */}
            {blogs.map((blog, idx) => (
              <p key={idx}>{blog}</p>
 ))}
          </div>
        </div>
 )}
    </>
 );
}

// Main App component
function App() {
  // Create promises for authors and blogs
  const authorsPromise = getAuthors();
  const blogsPromise = getBlogs();

  return (
    // Use Suspense to handle loading states
    <Suspense fallback={<div>Loading Authors...</div>}>
      <RetrieveAuthors
        authorsPromise={authorsPromise}
        blogsPromise={blogsPromise}
      />
    </Suspense>
 );
}

export default App;

На Π΄Π°Π½Π½ΠΎΠΌ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΈ дСмонстрируСтся, Ρ‡Ρ‚ΠΎ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ интСрфСйс обновляСтся Ρ‚ΠΎΠ»ΡŒΠΊΠΎ послС Ρ‚ΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ всС промисы Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠ»ΠΈΡΡŒ.

ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ интСрфСйс обновляСтся Ρ‚ΠΎΠ»ΡŒΠΊΠΎ послС Ρ‚ΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ всС промисы Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠ»ΠΈΡΡŒ

Π£Π»ΡƒΡ‡ΡˆΠ΅Π½ΠΈΠ΅ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ ref Π² пропсах

Π’ React 19 Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Ρ‚ΡŒ ref ΠΊΠ°ΠΊ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎΠ΅ свойство ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°, Π° Π½Π΅ ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ forwardRef для ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ ref ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρƒ. Π­Ρ‚ΠΎ позволяСт ΡΠΎΡ…Ρ€Π°Π½ΡΡ‚ΡŒ значСния ref ΠΌΠ΅ΠΆΠ΄Ρƒ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π°ΠΌΠΈ ΠΈ ΠΈΠ·Π±Π΅Π³Π°Ρ‚ΡŒ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… пСрСрисовок ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°.

Π’ΠΎΡ‚ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π½ΠΎΠ²ΠΎΠΉ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ ref ΠΊΠ°ΠΊ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎΠ³ΠΎ свойства ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°:

function NewRef({ ref }) {
  return <button ref={ref}>Click Me</button>;
}

//...
<NewRef ref={ref} />;

Π Π°Π½Π΅Π΅ ΠΌΡ‹ использовали forwardRef для опрСдСлСния ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° OldRef. Π­Ρ‚ΠΎΡ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄ позволяСт ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρƒ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ доступ ΠΊ ref, ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Π΅ΠΌΠΎΠΌΡƒ Π΅ΠΌΡƒ. Рассмотрим ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ:

const OldRef = forwardRef((props, ref) => {
  return (
    <button ref={ref} {...props}>
      {props.children}
    </button>
 );
});

//...
<OldRef ref={ref} onClick={handleClick}>
 Click me
</OldRef>;

ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° ΠΌΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹Ρ… Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°

React 19 Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³ Ρ‚Π΅Π³ΠΎΠ² ΠΌΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹Ρ… прямо Π² ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π΅ Π±Π΅Π· использования сторонних Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ, Ρ‚Π°ΠΊΠΈΡ… ΠΊΠ°ΠΊ react-helmet. Π’ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½ΠΎΠΌ Π½ΠΈΠΆΠ΅ ΠΊΠΎΠ΄Π΅ ΠΌΡ‹ обновляСм элСмСнты title ΠΈ meta нСпосрСдствСнно Π² ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π΅ App:

Назад
Π§Ρ‚ΠΎ Π½ΠΎΠ²ΠΎΠ³ΠΎ Π² React 19: 12 послСдних Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ ΠΈ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΉ
ΠœΠ°Ρ€Ρ‹Π΄Π΅Ρ€Π° Π£Π³ΠΎΡ€Π΄ΠΆΠΈ
ΠœΠ°Ρ€Ρ‹Π΄Π΅Ρ€Π° Π£Π³ΠΎΡ€Π΄ΠΆΠΈ
24 сСн 2024 Π³. Β· 9 ΠΌΠΈΠ½ чтСния

Π§Ρ‚ΠΎ Π½ΠΎΠ²ΠΎΠ³ΠΎ Π² React 19: 12 послСдних Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ ΠΈ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΉ
НаконСц-Ρ‚ΠΎ Π²Ρ‹ΡˆΠ΅Π» React 19! Он принСс с собой нСсколько интСрСсных ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΉ, начиная ΠΎΡ‚ компилятора React ΠΈ заканчивая Π²Π²Π΅Π΄Π΅Π½ΠΈΠ΅ΠΌ Π½ΠΎΠ²Ρ‹Ρ… Ρ…ΡƒΠΊΠΎΠ², ΡƒΠ»ΡƒΡ‡ΡˆΠ΅Π½Π½ΠΎΠΉ систСмой ΠΎΡ‚Ρ‡Π΅Ρ‚ΠΎΠ² ΠΎΠ± ΠΎΡˆΠΈΠ±ΠΊΠ°Ρ… ΠΈ Ρ‚. Π΄., ΠΈ Π² этой ΡΡ‚Π°Ρ‚ΡŒΠ΅ ΠΌΡ‹ рассмотрим ΠΎΠΊΠΎΠ»ΠΎ Π΄ΡŽΠΆΠΈΠ½Ρ‹ Π½ΠΎΠ²Π΅ΠΉΡˆΠΈΡ… Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ React.

ΠœΡ‹ рассмотрим Π΄ΡŽΠΆΠΈΠ½Ρƒ Π½ΠΎΠ²Ρ‹Ρ… Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ React 19. Π”Π°Π²Π°ΠΉΡ‚Π΅ Π½Π°Ρ‡Π½Π΅ΠΌ с Ρ‚ΠΎΠΉ, которая Π΄Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ отличаСтся, Π° Π·Π°Ρ‚Π΅ΠΌ ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΠΌ ΠΏΠΎ всСму списку.

ΠšΠΎΠΌΠΏΠΈΠ»ΡΡ‚ΠΎΡ€ React
Π­Ρ‚ΠΎ возглавляСт список ΠΊΠ°ΠΊ послСднСС Π΄ΠΎΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ ΠΊ React. React 18 ΠΈ Π½ΠΈΠΆΠ΅ Π½Π΅ ΠΈΠΌΠ΅Π»ΠΈ компилятора; вмСсто этого ΠΎΠ½ΠΈ использовали транспилятор. ОсновноС Ρ€Π°Π·Π»ΠΈΡ‡ΠΈΠ΅ ΠΌΠ΅ΠΆΠ΄Ρƒ Π½ΠΈΠΌΠΈ Π·Π°ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ транспилятор пСрСрисовываСт вСсь ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ ΠΏΡ€ΠΈ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΈ состояния, Π° компилятор β€” Π½Π΅Ρ‚. ΠšΠΎΠΌΠΏΠΈΠ»ΡΡ‚ΠΎΡ€ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ ΠΌΠ΅ΠΌΠΎΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ ΠΊΠΎΠ΄. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, большС Π½Π΅Ρ‚ Π½Π΅Π½ΡƒΠΆΠ½ΠΎΠ³ΠΎ ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎΠ³ΠΎ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π°, ΠΈ это заставило Π±Ρ‹ прилоТСния React Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ быстрСС.

Π”Π°Π²Π°ΠΉΡ‚Π΅ запустим ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½Ρ‹ΠΉ Π½ΠΈΠΆΠ΅ ΠΊΠΎΠ΄ Π² React 18 ΠΈ React 19 ΠΈ посмотрим Π½Π° Ρ€Π°Π·Π½ΠΈΡ†Ρƒ Π² Ρ‚ΠΎΠΌ, ΠΊΠ°ΠΊ происходит повторная визуализация ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ².

// Component to measure and log the time taken to render the header
function TimeToRender() {
  // Record the start time when the component begins rendering
  const startTime = performance.now();

  useEffect(() => {
    // Record the end time when the component has rendered
    const endTime = performance.now();
    // Log the time taken to render the component
    console.log(`CustomHeader render time: ${endTime - startTime}ms`);
 }, []); // Empty dependency array ensures this effect runs only once after the initial render

  return (
    <header>
      <h1>Counter App</h1>
    </header>
 );
}

// Main component of the Counter App
function CounterApp() {
  // State hook to manage the count value
  const [count, setCount] = useState(0);

  return (
    <>
      {/* Render the TimeToRender component */}
      <TimeToRender />
      <div>
        {/* Display the current count */}
        <p>{count}</p>
        {/* Button to increase the count */}
        <button onClick={() => setCount(count + 1)}>Increase</button>
        {/* Button to decrease the count */}
        <button onClick={() => setCount(count - 1)}>Decrease</button>
      </div>
    </>
 );
}

// Export the CounterApp component as the default export
export default CounterApp;
Код Π²Ρ‹ΡˆΠ΅ β€” это ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅-счСтчик, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ ΡƒΠ²Π΅Π»ΠΈΡ‡ΠΈΠ²Π°Π΅Ρ‚ ΠΈ ΡƒΠΌΠ΅Π½ΡŒΡˆΠ°Π΅Ρ‚ счСтчик ΠΏΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ ΠΊΠ½ΠΎΠΏΠΊΠΈ. Π£ Π½Π΅Π³ΠΎ Π΅ΡΡ‚ΡŒ функция TimeToRender, которая измСряСт врСмя, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΠ΅ для Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π° ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Ρ€Π°Π·, ΠΊΠΎΠ³Π΄Π° ΠΎΠ½ рСндСрится.

На рисункС Π½ΠΈΠΆΠ΅ ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ, ΠΊΠΎΠ³Π΄Π° ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ рСндСрится Π² компиляторС, ΠΈ врСмя, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΠ΅ для ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎΠ³ΠΎ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π°.

ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ (1)

На ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΈ Π½ΠΈΠΆΠ΅ ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ врСмя, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΠ΅ для ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎΠΉ Π²ΠΈΠ·ΡƒΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ всСго ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° Π² транспиляторС.

компилятор (1)

На ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΈ Π²Ρ‹ΡˆΠ΅ ΠΌΡ‹ Π²ΠΈΠ΄ΠΈΠΌ, Ρ‡Ρ‚ΠΎ транспилятор выполняСт ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΡƒΡŽ Π²ΠΈΠ·ΡƒΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ нСсколько Ρ€Π°Π·, ΠΈ врСмя ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎΠΉ Π²ΠΈΠ·ΡƒΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ ΡƒΠΌΠ΅Π½ΡŒΡˆΠ°Π΅Ρ‚ΡΡ с ΠΊΠ°ΠΆΠ΄Ρ‹ΠΌ Ρ‰Π΅Π»Ρ‡ΠΊΠΎΠΌ, Π² Ρ‚ΠΎ врСмя ΠΊΠ°ΠΊ компилятор выполняСт Π²ΠΈΠ·ΡƒΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π·.

РаньшС ΠΌΡ‹ Π±Ρ‹ использовали Ρ…ΡƒΠΊΠΈ memo , useMemo() ΠΈ useCallback() для достиТСния этого. Π­Ρ‚ΠΎ сдСлало Π±Ρ‹ эти Ρ…ΡƒΠΊΠΈ ΡƒΡΡ‚Π°Ρ€Π΅Π²ΡˆΠΈΠΌΠΈ. ΠšΡ€ΠΎΠΌΠ΅ Ρ‚ΠΎΠ³ΠΎ, Ρƒ нас Π±Ρ‹Π» Π±Ρ‹ Π±ΠΎΠ»Π΅Π΅ чистый ΠΈ мСньшС строк ΠΊΠΎΠ΄Π°.

НовыС ΠΊΡ€ΡŽΡ‡ΠΊΠΈ
Π₯ΡƒΠΊΠΈ β€” ΠΎΠ΄Π½Π° ΠΈΠ· самых популярных Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ React. Они ΠΏΠΎΠΌΠΎΠ³Π°ΡŽΡ‚ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄Π°ΠΌΠΈ состояния ΠΈ ΠΆΠΈΠ·Π½Π΅Π½Π½ΠΎΠ³ΠΎ Ρ†ΠΈΠΊΠ»Π°. React ΠΈΠΌΠ΅Π΅Ρ‚ встроСнныС Ρ…ΡƒΠΊΠΈ, Π° Ρ‚Π°ΠΊΠΆΠ΅ ΠΏΡ€Π΅Π΄Π»Π°Π³Π°Π΅Ρ‚ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ создания ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΡ… Ρ…ΡƒΠΊΠΎΠ².

Π’ React 19 Π±Ρ‹Π»ΠΎ Π²Π²Π΅Π΄Π΅Π½ΠΎ Ρ‡Π΅Ρ‚Ρ‹Ρ€Π΅ Π½ΠΎΠ²Ρ‹Ρ… Ρ…ΡƒΠΊΠ°:

ИспользованиС Transition Hook
Π₯ΡƒΠΊ useActionState​
Π₯ΡƒΠΊ useFormStatus​
ИспользованиСOptimistic Hook​
ИспользованиС Transition Hook
React 19 ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ использованиС asyncΡ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ Π² ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄Π°Ρ… для управлСния измСнСниями состояния, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΠΎΠ³ΡƒΡ‚ привСсти ΠΊ измСнСниям ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ интСрфСйса. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ useTransitionΡ…ΡƒΠΊ для обновлСния статуса состояния, Ρ‡Ρ‚ΠΎΠ±Ρ‹ автоматичСски ΠΏΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ, находится Π»ΠΈ ΠΎΠ½ΠΎ Π² состоянии оТидания ΠΈΠ»ΠΈ Π½Π΅Ρ‚.

Π­Ρ‚ΠΎ Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΡƒΠ΅Ρ‚, Ρ‡Ρ‚ΠΎ ΠΊΠΎΠ³Π΄Π° ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ запускаСт ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅, ΠΎΠ½ΠΎ обрабатываСтся Π³Π»Π°Π΄ΠΊΠΎ. ΠšΡ€ΠΎΠΌΠ΅ Ρ‚ΠΎΠ³ΠΎ, ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ интСрфСйс Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΡ‚Ρ€Π°ΠΆΠ°Ρ‚ΡŒ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎΠ΅ состояниС Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ async. Π”Π°Π²Π°ΠΉΡ‚Π΅ рассмотрим ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΊΠΎΠ΄Π°.

Код Π½ΠΈΠΆΠ΅ β€” это ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ добавляСт Π°Π»Ρ„Π°Π²ΠΈΡ‚ Π² список. ΠŸΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ ΠΊΠ½ΠΎΠΏΠΊΠΈ добавлСния ΠΎΠ½ΠΎ ΠΆΠ΄Π΅Ρ‚ 4 сСкунды, ΠΏΡ€Π΅ΠΆΠ΄Π΅ Ρ‡Π΅ΠΌ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π°Π»Ρ„Π°Π²ΠΈΡ‚ Π² список. ΠœΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ автоматичСски ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ состояниС оТидания с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ startTransition asyncΡ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ.

import React, { useState, useTransition } from "react";

// Function to create a delay for a given number of milliseconds
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

// Asynchronous function to add an alphabet to the list after a delay
async function addAlphabetToList(alphabet) {
  await delay(4000);
  return null;
}

// Component to add an alphabet to a list
function AlphabetAdder() {
  const [alphabet, setAlphabet] = useState("");
  const [error, setError] = useState(null);
  // State and function for transition
  const [isPending, startTransition] = useTransition();
  const [alphabetList, setAlphabetList] = useState([]); // State to store the list of alphabets

  // Function to handle adding an alphabet to the list
  const handleAddAlphabet = async () => {
    startTransition(async () => {
      const error = await addAlphabetToList(alphabet); // Add alphabet to the list with delay
      if (error) {
        setError(error);
 } else {
        setAlphabetList([...alphabetList, alphabet]);
 }
 });
 };

  // Log the pending state
  console.log("Pending:", isPending);

  return <></>;
}
На ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΈ Π½ΠΈΠΆΠ΅ ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ, Ρ‡Ρ‚ΠΎ состояниС оТидания сохраняСтся trueΠ΄ΠΎ Ρ‚Π΅Ρ… ΠΏΠΎΡ€, ΠΏΠΎΠΊΠ° Π°Π»Ρ„Π°Π²ΠΈΡ‚ Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ Π² список Ρ‡Π΅Ρ€Π΅Π· 4 с.

ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄Π°

Π­Ρ‚ΠΎ контрастируСт с ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΠΌΠΈ вСрсиями, Π³Π΄Π΅ ΠΌΡ‹ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π»ΠΈ состояниС оТидания Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽ, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ setIsPendingdingΡ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ для установки состояния Π² Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ trueΠΈΠ»ΠΈ false.

import React, { useState } from "react";

// Function to create a delay
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

// Async function to simulate adding an alphabet to a list after a delay
async function addAlphabetToList(alphabet) {
  await delay(4000);
  return null;
}

function AlphabetAdder() {
  const [alphabet, setAlphabet] = useState("");
  const [error, setError] = useState(null);
  // State to manage the pending state
  const [isPending, setIsPending] = useState(false);
  const [alphabetList, setAlphabetList] = useState([]);

  // Function to handle adding the alphabet
  const handleAddAlphabet = async () => {
    setIsPending(true);
    // Add the alphabet to the list after the delay
    const error = await addAlphabetToList(alphabet);
    if (error) {
      setError(error);
 } else {
      setAlphabetList([...alphabetList, alphabet]);
 }
    setIsPending(false);
 };

  // Log the pending state
  console.log("Pending:", isPending);

  return <></>;
}
export default AlphabetAdder;
Π₯ΡƒΠΊ useActionState
Π₯ΡƒΠΊ useActionStateΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для управлСния измСнСниями состояния Π² ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠΌ интСрфСйсС, ΠΊΠ°ΠΊ ΠΈ useTransitionΡ…ΡƒΠΊ. Π§Ρ‚ΠΎ ΠΎΡ‚Π»ΠΈΡ‡Π°Π΅Ρ‚ Π΅Π³ΠΎ ΠΎΡ‚ useTransitionΡ…ΡƒΠΊΠ° Π²Ρ‹ΡˆΠ΅, Ρ‚Π°ΠΊ это Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ ΠΎΠ½ Π½Π°Π·Π½Π°Ρ‡Π°Π΅Ρ‚ состояния error, action, ΠΈ pendingΠ² ΠΎΠ΄Π½ΠΎΠΉ строкС ΠΊΠΎΠ΄Π° вмСсто Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… строк, ΠΊΠ°ΠΊ ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ Π²Ρ‹ΡˆΠ΅. ΠšΡ€ΠΎΠΌΠ΅ Ρ‚ΠΎΠ³ΠΎ, useTransitionΡ…ΡƒΠΊ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ состояниС оТидания.

ΠœΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠ΅Ρ€Π΅ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΊΠΎΠ΄ Π²Ρ‹ΡˆΠ΅, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ useActionState, Ρ‡Ρ‚ΠΎ даст Π½Π°ΠΌ мСньшС строк ΠΊΠΎΠ΄Π°.

const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

async function addAlphabetToList(name) {
  await delay(4000);
  return null;
}

function AlphabetAdder() {
  const [error, submitAction, isPending] = useActionState(
    async (previousState, formData) => {
      const error = await addAlphabetToList(formData.get("name"));
      if (error) {
        return error;
 }

      return null;
 },
    null,
 );

  console.log("Pending:", isPending);
  return <></>;
}
Π’ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½ΠΎΠΌ Π²Ρ‹ΡˆΠ΅ ΠΊΠΎΠ΄Π΅ useActionStateΡ…ΡƒΠΊ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для автоматичСской ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ состояний error, submitActionΠΈ isPendingΠ±Π΅Π· явного опрСдСлСния Π΅Π³ΠΎ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ useStateΡ…ΡƒΠΊΠ° ΠΈΠ»ΠΈ useTransitionΡ…ΡƒΠΊΠ° для ΠΎΠΆΠΈΠ΄Π°ΡŽΡ‰ΠΈΡ… состояний, ΠΊΠ°ΠΊ ΠΌΡ‹ Π΄Π΅Π»Π°Π»ΠΈ Ρ€Π°Π½Π΅Π΅.

Π₯ΡƒΠΊ useFormStatus
Π₯ΡƒΠΊ useFormStatusΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для доступа ΠΊ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ ΠΎΠ± ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½Π½ΠΎΠΉ Ρ„ΠΎΡ€ΠΌΠ΅. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ доступ ΠΊ ΡΠΎΡΡ‚ΠΎΡΠ½ΠΈΡŽ Ρ„ΠΎΡ€ΠΌΡ‹, находящСйся Π² Ρ€Π΅ΠΆΠΈΠΌΠ΅ оТидания ΠΈΠ»ΠΈ Π½Π΅Ρ‚.

Π’ΠΎΡ‚ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΊΠΎΠ΄Π°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ useFormStatusΡ…ΡƒΠΊ для доступа ΠΊ ΡΠΎΡΡ‚ΠΎΡΠ½ΠΈΡŽ оТидания Ρ„ΠΎΡ€ΠΌΡ‹.

function FormStatusButton() {
  const { isPending } = useFormStatus();
  return (
    <div>
      <button type="submit" disabled={isPending}>
        {isPending ? "Adding..." : "Add"}
      </button>
    </div>
 );
}
РаньшС для доступа ΠΊ ΡΠΎΡΡ‚ΠΎΡΠ½ΠΈΡŽ оТидания ΠΌΡ‹ Π±Ρ‹ ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Π»ΠΈ состояниС с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ prop. Π’ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ ΠΊΠΎΠ΄Π° Π½ΠΈΠΆΠ΅ ΠΌΡ‹ ΠΏΠ΅Ρ€Π΅Π΄Π°Π»ΠΈ isPendingсостояниС ΠΊΠ°ΠΊ свойство Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ CustomButtonдля доступа ΠΊ Π½Π΅ΠΌΡƒ Π² ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Π΅ return.

function CustomButton({ isPending }) {
  return (
    <div>
      <button type="submit" disabled={isPending}>
        {isPending ? "Adding..." : "Add"}
      </button>
    </div>
 );
}
ИспользованиСOptimistic Hook
Π­Ρ‚ΠΎΡ‚ Ρ…ΡƒΠΊ позволяСт Π½Π°ΠΌ ΠΌΠ³Π½ΠΎΠ²Π΅Π½Π½ΠΎ ΠΎΠ±Π½ΠΎΠ²Π»ΡΡ‚ΡŒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ интСрфСйс ΠΏΡ€ΠΈ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΈ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ состояния, Π½Π΅ доТидаясь asyncΠ·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ дСйствия. НапримСр, Π² Ρ‡Π°Ρ‚-прилоТСниях, ΠΊΠΎΠ³Π΄Π° отправляСтся сообщСниС, ΠΎΠ½ΠΎ Π½Π΅ΠΌΠ΅Π΄Π»Π΅Π½Π½ΠΎ обновляСтся Π² ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠΌ интСрфСйсС, Π΄Π°ΠΆΠ΅ Π΄ΠΎ Ρ‚ΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ ΠΎΠ½ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½ΠΎ ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚Π΅Π»ΡŽ, ΠΈ Π² Π±ΠΎΠ»ΡŒΡˆΠΈΠ½ΡΡ‚Π²Π΅ случаСв Π΄ΠΎΠ±Π°Π²Π»ΡΡŽΡ‚ΡΡ Π³Π°Π»ΠΎΡ‡ΠΊΠΈ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π·Π½Π°Ρ‚ΡŒ, ΠΊΠΎΠ³Π΄Π° ΠΎΠ½ΠΎ ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ доставлСно.

Код Π½ΠΈΠΆΠ΅ ΠΈΠ»Π»ΡŽΡΡ‚Ρ€ΠΈΡ€ΡƒΠ΅Ρ‚ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π·Π°Π΄Π°Ρ‡, Π³Π΄Π΅ ΠΏΡ€ΠΈ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠΈ Π·Π°Π΄Π°Ρ‡ΠΈ Π² список Π·Π°Π΄Π°Ρ‡ ΠΎΠ½Π° ΠΏΡ€ΠΎΡ…ΠΎΠ΄ΠΈΡ‚ Ρ‡Π΅Ρ€Π΅Π· asyncΡ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ ΠΈ, Π½Π°ΠΊΠΎΠ½Π΅Ρ†, обновляСтся Π² ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠΌ интСрфСйсС Ρ‡Π΅Ρ€Π΅Π· 4 с. ΠœΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ useOptimisticΡ…ΡƒΠΊ для Π½Π΅ΠΌΠ΅Π΄Π»Π΅Π½Π½ΠΎΠ³ΠΎ отобраТСния Π΄ΠΎΠ±Π°Π²Π»Π΅Π½Π½ΠΎΠΉ Π·Π°Π΄Π°Ρ‡ΠΈ Π² ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠΌ интСрфСйсС, Π΄Π°ΠΆΠ΅ Π΄ΠΎ Ρ‚ΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ закончится 4-сСкундная ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ.

function App({ initialTasks }) {
  // State to hold the tasks
  const [tasks, setTasks] = useState(initialTasks);
  // Optimistic UI state for tasks
  const [optimisticTask, addOptimisticTasks] = useOptimistic(tasks);

  const inputRef = useRef(null);

  // Handle form submission
  async function handleSubmit(e) {
    if (inputRef.current == null) return;

    // Create an optimistic task
    const optimisticTask = {
      id: crypto.randomUUID(),
      title: inputRef.current.value,
 };

    // Add the optimistic task to the state
    addOptimisticTasks((prev) => [...prev, optimisticTask]);

    // Create a new task (simulating server creation)
    const newTask = await createTask(inputRef.current.value);
    // Add the new task to the state
    setTasks((prev) => [...prev, newTask]);
 }

  return (
    <>
      <form action={handleSubmit}>
        <label>Add New Task</label>
        <br />
        <input ref={inputRef} required />
        <br />
        <button>Create Task</button>
      </form>
      <ul>
        {/* Render the list of optimistic tasks */}
        {optimisticTask.map((task) => (
          <li key={task.id}>{task.title}</li>
 ))}
      </ul>
    </>
 );
}

// Function that simulates creating a task on the server
function createTask(title) {
  return delay(
 { id: crypto.randomUUID(), title: `${title} - in the server` },
    4000,
 );
}

// Function to create a delay
function delay(value, duration) {
  return new Promise((resolve) => {
    setTimeout(() => resolve(value), duration);
 });
}

export default App;
На ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΈ Π½ΠΈΠΆΠ΅ ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ, ΠΊΠ°ΠΊ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ интСрфСйс обновляСтся Π½Π΅ΠΌΠ΅Π΄Π»Π΅Π½Π½ΠΎ. Π§Π΅Ρ€Π΅Π· 4 сСкунды Π·Π°Π΄Π°Ρ‡Π° замСняСтся Π½Π° Ρ‚Ρƒ, Ρ‡Ρ‚ΠΎ Π½Π° сСрвСрС.

ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄Π° (1)

РаньшС ΠΌΡ‹ Π±Ρ‹ ΡΠΏΡ€Π°Π²ΠΈΠ»ΠΈΡΡŒ с этим, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ useStateΡ…ΡƒΠΊ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ оптимистичным ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ΠΌ Π·Π°Π΄Π°Ρ‡ ΠΈ ΠΎΠ±Π½ΠΎΠ²Π»ΡΡ‚ΡŒ Π΅Π³ΠΎ фактичСской Π·Π°Π΄Π°Ρ‡Π΅ΠΉ.

const [tasks, setTasks] = useState(initialTasks);
// Setting optimistic tasks using the useState hook
const [optimisticTasks, setOptimisticTasks] = useState(initialTasks);

const inputRef = useRef(null);

async function handleSubmit(e) {
  e.preventDefault(); // Prevent default form submission

  if (inputRef.current == null) return;

  const optimisticTask = {
    id: crypto.randomUUID(),
    title: inputRef.current.value,
 };

  // Add the optimistic task immediately
  setOptimisticTasks((prev) => [...prev, optimisticTask]);

  // Create the actual task with a delay
  const newTask = await createTask(inputRef.current.value);
  setTasks((prev) => [...prev, newTask]);
  setOptimisticTasks((prev) =>
    prev.map((task) => (task.id === optimisticTask.id ? newTask : task)),
 );
}
Π’ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½ΠΎΠΌ Π²Ρ‹ΡˆΠ΅ ΠΊΠΎΠ΄Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ useStateΡ…ΡƒΠΊ для добавлСния optimisticTasksоптимистичных ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΉ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ интСрфСйса ΠΈ Π΅Π³ΠΎ функция-установщик setOptimistictask для обновлСния состояния.

Новый API - ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅
API use позволяСт ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ PromisesΠΈ async-await. Он ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Promise, Π° Π½Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, ΠΊΠΎΠ³Π΄Π° PromiseΠ·Π°Π²Π΅Ρ€ΡˆΠ°Π΅Ρ‚ Ρ€Π°Π±ΠΎΡ‚Ρƒ Π΄ΠΎ обновлСния ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ интСрфСйса. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π²Ρ‹Π·Ρ‹Π²Π°Ρ‚ΡŒ этот API Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΠ² if ΠΈ Ρ†ΠΈΠΊΠ»ΠΎΠ². Π’Ρ‹ Ρ‚Π°ΠΊΠΆΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π²Ρ‹Π·Ρ‹Π²Π°Ρ‚ΡŒ этот API Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΠ² if ΠΈ Ρ†ΠΈΠΊΠ»ΠΎΠ².

Π”Π°Π²Π°ΠΉΡ‚Π΅ рассмотрим ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΊΠΎΠ΄Π°. Он содСрТит 2 asyncΡ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΈΠΌΠΈΡ‚ΠΈΡ€ΡƒΡŽΡ‚ Π²Ρ‹Π±ΠΎΡ€ΠΊΡƒ Π΄Π°Π½Π½Ρ‹Ρ… с Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠΎΠΉ, ΠΊΠ°ΠΊ это ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ Π±Ρ‹Π²Π°Π΅Ρ‚ ΠΏΡ€ΠΈ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠ΅ Π΄Π°Π½Π½Ρ‹Ρ… Π½Π° сСрвСр. Он Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ список Π°Π²Ρ‚ΠΎΡ€ΠΎΠ² ΠΈ Π±Π»ΠΎΠ³ΠΎΠ² послС Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠΈ Π² 4 ΠΈ 2 сСкунды соотвСтствСнно, ΠΏΠ΅Ρ€Π΅Π΄ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ΠΌ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ интСрфСйса этими значСниями.

import { use, Suspense } from "react";

// Create a delay
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

// Async function that fetches the list of blogs after the delay
const getBlogs = async () => {
  await delay(4000);
  return ["OpenReplay", "Devto", "Medium"];
};

// Async function that fetches the list of authors after a delay
const getAuthors = async () => {
  await delay(2000);
  return {
    isFetchUsers: true,
    authors: ["Mary Chidera", "Ugorji Marydera", "Ken Erics"],
 };
};

// Component to retrieve and display authors and blogs
function RetrieveAuthors({ authorsPromise, blogsPromise }) {
  // Use the authorsPromise to get the authors' data
  const { isFetchUsers, authors } = use(authorsPromise);

  console.log("Authors Promise Done: ", authors);

  let blogs;
  // If users are fetched, use the blogsPromise to get the blogs data
  if (isFetchUsers) blogs = use(blogsPromise);

  console.log("Blogs Promise is done :", blogs);

  return (
    <>
      <div>
        <h2>Authors</h2>
        <div>
          {/* Map over the authors array and display each author */}
          {authors.map((author, idx) => (
            <p key={idx}>{author}</p>
 ))}
        </div>
      </div>
      {blogs && (
        <div>
          <h2>Top Blogs</h2>
          <div>
            {/* Map over the blogs array and display each blog */}
            {blogs.map((blog, idx) => (
              <p key={idx}>{blog}</p>
 ))}
          </div>
        </div>
 )}
    </>
 );
}

// Main App component
function App() {
  // Create promises for authors and blogs
  const authorsPromise = getAuthors();
  const blogsPromise = getBlogs();

  return (
    // Use Suspense to handle loading states
    <Suspense fallback={<div>Loading Authors...</div>}>
      <RetrieveAuthors
        authorsPromise={authorsPromise}
        blogsPromise={blogsPromise}
      />
    </Suspense>
 );
}

export default App;
На ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΈ Π½ΠΈΠΆΠ΅ ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ, ΠΊΠ°ΠΊ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ интСрфСйс обновляСтся Ρ‚ΠΎΠ»ΡŒΠΊΠΎ послС Ρ‚ΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ всС PromisesΠ·Π°Π³Ρ€ΡƒΠ·ΠΈΠ»ΠΎΡΡŒ.

ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ

Бсылка ΠΊΠ°ΠΊ ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΉ Ρ€Π΅ΠΊΠ²ΠΈΠ·ΠΈΡ‚
Бсылки ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‚ Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚ΡŒ доступ ΠΊ элСмСнтам DOM ΠΈ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ с Π½ΠΈΠΌΠΈ. Они ΡΠΎΡ…Ρ€Π°Π½ΡΡŽΡ‚ свои значСния ΠΌΠ΅ΠΆΠ΄Ρƒ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π°ΠΌΠΈ ΠΈ Π½Π΅ Π²Ρ‹Π·Ρ‹Π²Π°ΡŽΡ‚ ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎΠ³ΠΎ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π° ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°.

Π’ React 19 Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Ρ‚ΡŒ refΠΊΠ°ΠΊ ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΉ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ propвмСсто использования forwardRefдля ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ a refΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρƒ.

Π’ΠΎΡ‚ новая рСализация refΠΎΠ±Ρ‹Ρ‡Π½ΠΎΠ³ΠΎ prop.

function NewRef({ ref }) {
  return <button ref={ref}>Click Me</button>;
}

//...
<NewRef ref={ref} />;
Π’ΠΎΡ‚ ΠΊΠ°ΠΊ ΠΌΡ‹ Π±Ρ‹ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π»ΠΈ это Ρ€Π°Π½Π΅Π΅. Как ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ Π½ΠΈΠΆΠ΅, ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ forwardRefдля опрСдСлСния OldRefΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°. The forwardRefΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ propsΠΈ a ref. refΠ’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ ΠΊ Π½Π΅ΠΌΡƒ доступ button.

const OldRef = forwardRef((props, ref) => {
  return (
    <button ref={ref} {...props}>
      {props.children}
    </button>
 );
});

//...
<OldRef ref={ref} onClick={handleClick}>
 Click me
</OldRef>;
ДСйствиС
Π’ Ρ„ΠΎΡ€ΠΌΠ°Ρ… Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Ρ‚ΡŒ свойство дСйствия . Π­Ρ‚ΠΎ propΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ asyncфункция ΠΈΠ»ΠΈ URL. Π€ΠΎΡ€ΠΌΠ° Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒΡΡ action propΠΏΡ€ΠΈ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠ΅ Ρ„ΠΎΡ€ΠΌΡ‹.

ΠœΡ‹ Ρ‚Π°ΠΊΠΆΠ΅ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ доступ ΠΊ полям Π²Π²ΠΎΠ΄Π° ΠΈ элСмСнтам Ρ„ΠΎΡ€ΠΌΡ‹, ΠΏΠ΅Ρ€Π΅Π΄Π°Π² ΠΈΡ… formDataΡ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ getAPI.

function Form() {
  const addBlogName = (formData) => {
    const blogName = formData.get("blogName");
    console.log(`You submitted '${blogName}'`);
 };

  return (
    <form action={addBlogName}>
      <input name="blogName" />
      <button type="submit">Search</button>
    </form>
 );
}

export default Form;
РаньшС ΠΌΡ‹ Π±Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΈ доступ ΠΊ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½ΠΎΠΌΡƒ ΠΈΠΌΠ΅Π½ΠΈ, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ event.

const addBlogName = (event) => {
  event.preventDefault();
  const blogName = event.target.elements.blogName.value;
  console.log(`You submitted '${blogName}'`);
};
Π’ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½ΠΎΠΉ Π²Ρ‹ΡˆΠ΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ addBlogNameΠΌΡ‹ Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ обращаСмся ΠΊ Π·Π½Π°Ρ‡Π΅Π½ΠΈΡŽ Π²ΠΎ Π²Ρ…ΠΎΠ΄Π½ΠΎΠΌ элСмСнтС, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ blogNameдля event.target.elementsдоступа ΠΊ элСмСнту ΠΈ Π΅Π³ΠΎ свойству.

ΠšΠΎΠ½Ρ‚Π΅ΠΊΡΡ‚ ΠΊΠ°ΠΊ поставщик
Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ контСкст Π² качСствС поставщика Π² вашСм ΠΊΠΎΠ΄Π΅. РаньшС, ΠΊΠΎΠ³Π΄Π° Π±Ρ‹ ΠΌΡ‹ Π½ΠΈ Ρ…ΠΎΡ‚Π΅Π»ΠΈ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ context, Π½Π°ΠΌ ΠΏΡ€ΠΈΡ…ΠΎΠ΄ΠΈΠ»ΠΎΡΡŒ Π΄Π΅Π»Π°Ρ‚ΡŒ contextName.Provider, Π° Π·Π°Ρ‚Π΅ΠΌ ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Ρ‚ΡŒ ΠΏΠΎΡ‚ΠΎΠΌΠΊΠΎΠ². Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π½Π°ΠΌ большС Π½Π΅ Π½ΡƒΠΆΠ½ΠΎ этого Π΄Π΅Π»Π°Ρ‚ΡŒ, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ Π²Ρ‹Π·Ρ‹Π²Π°Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ имя Π±Π΅Π· .Provider.

Π’ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½ΠΎΠΌ Π½ΠΈΠΆΠ΅ ΠΊΠΎΠ΄Π΅ ΠΌΡ‹ создали контСкст с ΠΈΠΌΠ΅Π½Π΅ΠΌ lightModeContextΠΈ Π²Ρ‹Π·Π²Π°Π»ΠΈ Π΅Π³ΠΎ нСпосрСдствСнно Π² ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Π΅ return.

//Context we created
const lightModeContext = createContext({ theme: "light" });

//New method of calling the context directly as a provider
function App({ children }) {
  return <lightModeContext value="dark">Children</lightModeContext>;
}
РаньшС Π½Π°ΠΌ ΠΏΡ€ΠΈΡˆΠ»ΠΎΡΡŒ Π±Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚ΡŒ доступ ΠΊ созданному Π½Π°ΠΌΠΈ контСксту, вызывая lightModeContext.Provider.

//old method of calling the context with the .Provider
function App({ children }) {
  return <lightModeContext.Provider value="light"></lightModeContext.Provider>;
}
ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° ΠΌΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹Ρ… Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°
React 19 ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³ Ρ‚Π΅Π³ΠΎΠ² ΠΌΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹Ρ… Π² ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π΅. РаньшС ΠΌΡ‹ Π±Ρ‹ Π΄Π΅Π»Π°Π»ΠΈ это с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ сторонних Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ, Ρ‚Π°ΠΊΠΈΡ… ΠΊΠ°ΠΊ react-helmet .

Π’ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½ΠΎΠΌ Π½ΠΈΠΆΠ΅ ΠΊΠΎΠ΄Π΅ ΠΌΡ‹ Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ обновляСм элСмСнты titleΠΈ metaΠ² AppΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π΅.

function App({ post }) {
  return (
    <article>
      <h1>{post.title}</h1>
      {/*meta tags */}
      <title>{title}</title>
      <meta name="description" content="post" />
      <meta name="keywords" content={post.keywords} />
    </article>
 );
}

Π’ΠΎΡ‚ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Ρ‚ΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ ΠΌΡ‹ Π΄Π΅Π»Π°Π»ΠΈ это Π² Π±ΠΎΠ»Π΅Π΅ Ρ€Π°Π½Π½ΠΈΡ… вСрсиях с использованиСм Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ react-helmet. Π’ этом ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ ΠΌΡ‹ обновляли элСмСнты title ΠΈ meta Ρ‡Π΅Ρ€Π΅Π· react-helmet:

import React from 'react';
import { Helmet } from 'react-helmet';

function App({ post }) {
  return (
    <article>
      <h1>{post.title}</h1>
      <Helmet>
        <title>{post.title}</title>
        <meta name="description" content={post.description} />
        <meta name="keywords" content={post.keywords} />
      </Helmet>
      {/* Other content of your component */}
    </article>
 );
}

export default App;

Π’ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½ΠΎΠΌ Π²Ρ‹ΡˆΠ΅ ΠΊΠΎΠ΄Π΅ для установки элСмСнтов title ΠΈ meta ΠΌΡ‹ использовали ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ Helmet ΠΈΠ· Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ react-helmet.

Π£Π»ΡƒΡ‡ΡˆΠ΅Π½Π½Ρ‹Π΅ ΠΎΡ‚Ρ‡Π΅Ρ‚Ρ‹ ΠΎΠ± ΠΎΡˆΠΈΠ±ΠΊΠ°Ρ…

Ошибки Π² Π½ΠΎΠ²ΠΎΠΉ вСрсии React 19 стали Π²Ρ‹Π³Π»ΡΠ΄Π΅Ρ‚ΡŒ ΠΌΠ΅Π½Π΅Π΅ многословно ΠΈ Π±ΠΎΠ»Π΅Π΅ Ρ‡ΠΈΡ‚Π°Π΅ΠΌΠΎ. Π’Π΅ΠΏΠ΅Ρ€ΡŒ вмСсто дублирования ошибок Π² консоли React 19 пытаСтся ΠΏΡ€Π΅Π΄ΠΎΡΡ‚Π°Π²ΠΈΡ‚ΡŒ ΠΎΠ΄Π½Ρƒ ΠΎΡˆΠΈΠ±ΠΊΡƒ с ΠΏΠΎΠ»Π½ΠΎΠΉ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠ΅ΠΉ ΠΎ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ΅. На ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΈ Π½ΠΈΠΆΠ΅ ΠΏΠΎΠΊΠ°Π·Π°Π½Π° ошибка, возникшая Π² ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π΅ ErrorComponent Π² React 18.

Ошибка, возникшая Π² ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π΅ ErrorComponent Π² React 18

Π’ΠΎΡ‚ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅, Π΄Π΅ΠΌΠΎΠ½ΡΡ‚Ρ€ΠΈΡ€ΡƒΡŽΡ‰Π΅Π΅ Ρ‚Ρƒ ΠΆΠ΅ ΠΎΡˆΠΈΠ±ΠΊΡƒ, ΠΊΠ°ΠΊ ΠΈ Π² React 19, Π½ΠΎ ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²Π»Π΅Π½Π½ΡƒΡŽ Π² ΠΎΡ‚Ρ‡Π΅Ρ‚Π΅ React 18.

Ошибка, возникшая Π² ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π΅ ErrorComponent Π² React 19

Π—Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅

React 19 прСдставляСт Π·Π°Ρ…Π²Π°Ρ‚Ρ‹Π²Π°ΡŽΡ‰ΠΈΠ΅ Π½ΠΎΠ²Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ ΡƒΠ»ΡƒΡ‡ΡˆΠ°ΡŽΡ‚ ΠΎΠΏΡ‹Ρ‚ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΎΠ². ΠœΡ‹ осмыслили Ρ‚Π°ΠΊΠΈΠ΅ Π½ΠΎΠ²Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, ΠΊΠ°ΠΊ компилятор, способный Ρ€Π΅ΡˆΠ°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎΠ³ΠΎ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Π°, Π½ΠΎΠ²Ρ‹Π΅ Ρ…ΡƒΠΊΠΈ для ΡƒΠ»ΡƒΡ‡ΡˆΠ΅Π½ΠΈΡ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ ΠΎΠΏΡ‹Ρ‚Π°, Π° Ρ‚Π°ΠΊΠΆΠ΅ ΡƒΠ»ΡƒΡ‡ΡˆΠ΅Π½Π½Ρ‹Π΅ ΠΎΡ‚Ρ‡Π΅Ρ‚Ρ‹ ΠΎΠ± ΠΎΡˆΠΈΠ±ΠΊΠ°Ρ…, ΠΏΡ€Π΅Π΄ΠΎΡΡ‚Π°Π²Π»ΡΡŽΡ‰ΠΈΠ΅ Π±ΠΎΠ»Π΅Π΅ Π»Π°ΠΊΠΎΠ½ΠΈΡ‡Π½Ρ‹Π΅ сообщСния ΠΎΠ± ΠΎΡˆΠΈΠ±ΠΊΠ°Ρ….

Π›Π£Π§Π¨Π˜Π• БВАВЬИ ПО Π’Π•ΠœΠ•