題外話
React 18 是一次重大的更新,併發模式對現有機制和代碼影響很大,所以要了解到底 18 更新了啥很重要。
原文:https://reactjs.org/blog/2022/03/29/react-v18.html#changelog
React
- Add
useTransition
anduseDeferredValue
to separate urgent updates from transitions. (#10426, #10715, #15593, #15272, #15578, #15769, #17058, #18796, #19121, #19703, #19719, #19724, #20672, #20976 by @acdlite, @lunaruan, @rickhanlonii, and @sebmarkbage) - Add
useId
for generating unique IDs. (#17322, #18576, #22644, #22672, #21260 by @acdlite, @lunaruan, and @sebmarkbage) - Add
useSyncExternalStore
to help external store libraries integrate with React. (#15022, #18000, #18771, #22211, #22292, #22239, #22347, #23150 by @acdlite, @bvaughn, and @drarmstr) - Add
startTransition
as a version ofuseTransition
without pending feedback. (#19696 by @rickhanlonii) - Add
useInsertionEffect
for CSS-in-JS libraries. (#21913 by @rickhanlonii) - Make Suspense remount layout effects when content reappears. (#19322, #19374, #19523, #20625, #21079 by @acdlite, @bvaughn, and @lunaruan)
- Make
<StrictMode>
re-run effects to check for restorable state. (#19523 , #21418 by @bvaughn and @lunaruan) - Assume Symbols are always available. (#23348 by @sebmarkbage)
- Remove
object-assign
polyfill. (#23351 by @sebmarkbage) - Remove unsupported
unstable_changedBits
API. (#20953 by @acdlite) - Allow components to render undefined. (#21869 by @rickhanlonii)
- Flush
useEffect
resulting from discrete events like clicks synchronously. (#21150 by @acdlite) - Suspense
fallback={undefined}
now behaves the same asnull
and isn’t ignored. (#21854 by @rickhanlonii) - Consider all
lazy()
resolving to the same component equivalent. (#20357 by @sebmarkbage) - Don’t patch console during first render. (#22308 by @lunaruan)
- Improve memory usage. (#21039 by @bgirard)
- Improve messages if string coercion throws (Temporal.*, Symbol, etc.) (#22064 by @justingrant)
- Use
setImmediate
when available overMessageChannel
. (#20834 by @gaearon) - Fix context failing to propagate inside suspended trees. (#23095 by @gaearon)
- Fix
useReducer
observing incorrect props by removing the eager bailout mechanism. (#22445 by @josephsavona) - Fix
setState
being ignored in Safari when appending iframes. (#23111 by @gaearon) - Fix a crash when rendering
ZonedDateTime
in the tree. (#20617 by @dimaqq) - Fix a crash when document is set to
null
in tests. (#22695 by @SimenB) - Fix
onLoad
not triggering when concurrent features are on. (#23316 by @gnoff) - Fix a warning when a selector returns
NaN
. (#23333 by @hachibeeDI) - Fix a crash when document is set to
null
in tests. (#22695 by @SimenB) - Fix the generated license header. (#23004 by @vitaliemiron)
- Add
package.json
as one of the entry points. (#22954 by @Jack) - Allow suspending outside a Suspense boundary. (#23267 by @acdlite)
- Log a recoverable error whenever hydration fails. (#23319 by @acdlite)
React DOM
- Add
createRoot
andhydrateRoot
. (#10239, #11225, #12117, #13732, #15502, #15532, #17035, #17165, #20669, #20748, #20888, #21072, #21417, #21652, #21687, #23207, #23385 by @acdlite, @bvaughn, @gaearon, @lunaruan, @rickhanlonii, @trueadm, and @sebmarkbage) - Add selective hydration. (#14717, #14884, #16725, #16880, #17004, #22416, #22629, #22448, #22856, #23176 by @acdlite, @gaearon, @salazarm, and @sebmarkbage)
- Add
aria-description
to the list of known ARIA attributes. (#22142 by @mahyareb) - Add
onResize
event to video elements. (#21973 by @rileyjshaw) - Add
imageSizes
andimageSrcSet
to known props. (#22550 by @eps1lon) - Allow non-string
<option>
children ifvalue
is provided. (#21431 by @sebmarkbage) - Fix
aspectRatio
style not being applied. (#21100 by @gaearon) - Warn if
renderSubtreeIntoContainer
is called. (#23355 by @acdlite)
React DOM Server
- Add the new streaming renderer. (#14144, #20970, #21056, #21255, #21200, #21257, #21276, #22443, #22450, #23247, #24025, #24030 by @sebmarkbage)
- Fix context providers in SSR when handling multiple requests. (#23171 by @frandiox)
- Revert to client render on text mismatch. (#23354 by @acdlite)
- Deprecate
renderToNodeStream
. (#23359 by @sebmarkbage) - Fix a spurious error log in the new server renderer. (#24043 by @eps1lon)
- Fix a bug in the new server renderer. (#22617 by @shuding)
- Ignore function and symbol values inside custom elements on the server. (#21157 by @sebmarkbage)
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
- Track late-mounted roots in Fast Refresh. (#22740 by @anc95)
- Add
exports
field topackage.json
. (#23087 by @otakustay)
Server Components (Experimental)
- Add Server Context support. (#23244 by @salazarm)
- Add
lazy
support. (#24068 by @gnoff) - Update webpack plugin for webpack 5 (#22739 by @michenly)
- Fix a mistake in the Node loader. (#22537 by @btea)
- Use
globalThis
instead ofwindow
for edge environments. (#22777 by @huozhi)
併發模式的內容介紹,參考另一篇:React 18 啓用併發模式 (Concurrent Mode),下面補充一些其他
useId
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
以防止多根應用程序中的衝突。 要配置,請參閱hydrateRoot
和ReactDOMServer
。
hydrateRoot()
hydrateRoot(element, container[, options])
Same as
createRoot()
, but is used to hydrate a container whose HTML contents were rendered byReactDOMServer
. 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 byReact.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
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
useInsertionEffect(didUpdate);
簽名與 useEffect
相同,但它在所有 DOM 突變 之前同步觸發。 在讀取 useLayoutEffect
中的佈局之前,使用它在 DOM 中注入樣式。 由於此掛鉤的範圍有限,因此此掛鉤無法訪問 refs 並且無法安排更新。
Note:
useInsertionEffect
應僅限於 css-in-js 庫作者。 首選useEffect
或useLayoutEffect
。