React 18 更新日誌 (Change log)

題外話

React 18 是一次重大的更新,併發模式對現有機制和代碼影響很大,所以要了解到底 18 更新了啥很重要。

原文:https://reactjs.org/blog/2022/03/29/react-v18.html#changelog

React

React DOM

React DOM Server

React DOM Test Utils

  • Throw when act is used in production. (#21686 by @acdlite)
  • Support disabling spurious act warnings with global.IS_REACT_ACT_ENVIRONMENT. (#22561 by @acdlite)
  • Expand act warning to cover all APIs that might schedule React work. (#22607 by @acdlite)
  • Make act batch updates. (#21797 by @acdlite)
  • Remove warning for dangling passive effects. (#22609 by @acdlite)

React Refresh

Server Components (Experimental)

併發模式的內容介紹,參考另一篇:React 18 啓用併發模式 (Concurrent Mode),下面補充一些其他

useId

原文:Hooks API Reference – React (reactjs.org)

const id = useId();

useId is a hook for generating unique IDs that are stable across the server and client, while avoiding hydration mismatches.

For a basic example, pass the id directly to the elements that need it:

function Checkbox() {
  const id = useId();
  return (
    <>
      <label htmlFor={id}>Do you like React?</label>
      <input id={id} type="checkbox" name="react"/>
    </>
  );
};

For multiple IDs in the same component, append a suffix using the same id:

function NameFields() {
  const id = useId();
  return (
    <div>
      <label htmlFor={id + '-firstName'}>First Name</label>
      <div>
        <input id={id + '-firstName'} type="text" />
      </div>
      <label htmlFor={id + '-lastName'}>Last Name</label>
      <div>
        <input id={id + '-lastName'} type="text" />
      </div>
    </div>
  );
}

Note:

useId 生成一個包含 : 標記的字符串。 這有助於確保令牌是唯一的,但在 CSS 選擇器或 API(如 querySelectorAll)中不受支持。

useId 支持 identifierPrefix 以防止多根應用程序中的衝突。 要配置,請參閱 hydrateRootReactDOMServer

hydrateRoot()

hydrateRoot(element, container[, options])

Same as createRoot(), but is used to hydrate a container whose HTML contents were rendered by ReactDOMServer. React will attempt to attach event listeners to the existing markup.

hydrateRoot accepts two options:

  • onRecoverableError: optional callback called when React automatically recovers from errors.
  • identifierPrefix: optional prefix React uses for ids generated by React.useId. Useful to avoid conflicts when using multiple roots on the same page. Must be the same prefix used on the server.

代碼上來說:

// react-dom
// line 15977
var localIdCounter = 0; 
// Used for ids that are generated completely client-side (i.e. not during
// hydration). This counter is global, so client ids are not stable across
// render attempts.
// line 15981
var globalClientIdCounter = 0;

// line 17207
function mountId() {
  var hook = mountWorkInProgressHook();
  var root = getWorkInProgressRoot(); 
  // TODO: In Fizz, id generation is specific to each server config. Maybe we
  // should do this in Fiber, too? Deferring this decision for now because
  // there's no other place to store the prefix except for an internal field on
  // the public createRoot object, which the fiber tree does not currently have
  // a reference to.

  var identifierPrefix = root.identifierPrefix;
  var id;

  if (getIsHydrating()) {
    var treeId = getTreeId(); // Use a captial R prefix for server-generated ids.

    id = ':' + identifierPrefix + 'R' + treeId; // Unless this is the first id at this level, append a number at the end
    // that represents the position of this useId hook among all the useId
    // hooks for this fiber.

    var localId = localIdCounter++;

    if (localId > 0) {
      id += 'H' + localId.toString(32);
    }

    id += ':';
  } else {
    // Use a lowercase r prefix for client-generated ids.
    var globalClientId = globalClientIdCounter++;
    id = ':' + identifierPrefix + 'r' + globalClientId.toString(32) + ':';
  }

  hook.memoizedState = id;
  return id;
}

function updateId() {
  var hook = updateWorkInProgressHook();
  var id = hook.memoizedState;
  return id;
}

useSyncExternalStore

原文:Hooks API Reference – React (reactjs.org)

const state = useSyncExternalStore(subscribe, getSnapshot[, getServerSnapshot]);

useSyncExternalStore 是一個推薦用於從外部數據源讀取和訂閱的鉤子,其方式與選擇性水合和時間切片等併發渲染功能兼容。

此方法返回 store 的值並接受三個參數:

  • subscribe: 函數註冊一個回調,每當 store 更改時調用該回調。
  • getSnapshot: 返回存儲的當前值的函數。
  • getServerSnapshot: 返回服務器渲染期間使用的快照的函數。

The most basic example simply subscribes to the entire store:

const state = useSyncExternalStore(store.subscribe, store.getSnapshot);

However, you can also subscribe to a specific field:

const selectedField = useSyncExternalStore(
  store.subscribe,
  () => store.getSnapshot().selectedField,
);

When server rendering, you must serialize the store value used on the server, and provide it to useSyncExternalStore. React will use this snapshot during hydration to prevent server mismatches:

const selectedField = useSyncExternalStore(
  store.subscribe,
  () => store.getSnapshot().selectedField,
  () => INITIAL_SERVER_SNAPSHOT.selectedField,
);

Note:

getSnapshot 必須返回一個緩存值。 如果連續多次調用 getSnapshot,則它必須返回相同的確切值,除非兩者之間有存儲更新。

提供了一個 shim 來支持發佈爲 use-sync-external-store/shim 的多個 React 版本。 此 shim 將在可用時首選 useSyncExternalStore,並在不可用時回退到用戶空間實現。

爲方便起見,我們還提供了一個 API 版本,該版本自動支持記憶 getSnapshot 發佈爲 use-sync-external-store/with-selector 的結果。

useInsertionEffect

原文:Hooks API Reference – React (reactjs.org)

useInsertionEffect(didUpdate);

簽名與 useEffect 相同,但它在所有 DOM 突變 之前同步觸發。 在讀取 useLayoutEffect 中的佈局之前,使用它在 DOM 中注入樣式。 由於此掛鉤的範圍有限,因此此掛鉤無法訪問 refs 並且無法安排更新。

Note:

useInsertionEffect 應僅限於 css-in-js 庫作者。 首選 useEffectuseLayoutEffect

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章