Skip to content

Commit f3b36f0

Browse files
committed
[feat] 更新 react 19 示例
1 parent d0428df commit f3b36f0

File tree

1 file changed

+287
-0
lines changed

1 file changed

+287
-0
lines changed

docs/frame/react_source.md

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,293 @@
33
> 转载自掘金文章:[React17 源码分析](https://juejin.cn/post/6898635086657224717)
44
> author: [xfz](https://juejin.cn/user/1415826705485128)
55
6+
## 19 版本特点
7+
8+
### Actions
9+
10+
- useTransition
11+
- useActionState
12+
- useFormState
13+
- useOptimistic
14+
- use
15+
16+
> React 19 新内容:[React19 new content](https://react.dev/blog/2024/12/05/react-19)
17+
18+
> 以下所有案例,直接复制到 codesandbox 中运行即可,缺少的 import 请自行补充。
19+
20+
- Actions: useTransition 任务执行方法及状态
21+
```javascript
22+
const updateName = () => {
23+
return new Promise((resolve, reject) => {
24+
setTimeout(() => {
25+
Math.random() > 0.5
26+
? resolve("finished")
27+
: reject(new Error("error get"));
28+
}, 1000);
29+
});
30+
};
31+
32+
export default function App() {
33+
const [name, setName] = useState("init");
34+
const [error, setError] = useState(null);
35+
const [isPending, startTransition] = useTransition();
36+
37+
const handleSubmit = () => {
38+
startTransition(async () => {
39+
const res = await updateName().catch((err) => setError(err));
40+
res && setName(res);
41+
});
42+
};
43+
44+
return (
45+
<div className="App">
46+
<h1>Hello {name}</h1>
47+
<h2>Start editing to see some magic happen!</h2>
48+
<button onClick={handleSubmit} disabled={isPending}>
49+
Update
50+
</button>
51+
{error && <p>{error.toString()}</p>}
52+
</div>
53+
);
54+
}
55+
```
56+
- Actions: useActionState
57+
```javascript
58+
59+
const updateName = (name) => {
60+
return new Promise((resolve, reject) => {
61+
setTimeout(() => {
62+
Math.random() > 0.5
63+
? resolve(`${name} finished`)
64+
: reject(new Error("error get"));
65+
}, 1000);
66+
});
67+
};
68+
69+
export default function App() {
70+
const [error, setError] = useState(null);
71+
const [state, submitAction, isPending] = useActionState(
72+
async (previousState, formData) => {
73+
setError(null);
74+
const state = await updateName(formData.get("name")).catch((err) =>
75+
setError(err)
76+
);
77+
if (state) {
78+
return state;
79+
}
80+
},
81+
null
82+
);
83+
84+
return (
85+
<form action={submitAction}>
86+
<input name="name" />
87+
<button type="submit" disabled={isPending}>
88+
Update
89+
</button>
90+
<p>state: {state}</p>
91+
{error && <p>{error.toString()}</p>}
92+
</form>
93+
);
94+
}
95+
```
96+
- Actions: useFormState
97+
```javascript
98+
function SubmitButton() {
99+
const { pending } = useFormStatus();
100+
101+
return (
102+
<div className="form_item">
103+
<button className="primary" type="submit" disabled={pending}>
104+
{pending ? "Submitting..." : "Submit"}
105+
</button>
106+
</div>
107+
);
108+
}
109+
110+
export default function App() {
111+
const [state, submitAction, isPending] = useActionState(
112+
async (previousState, formData) => {
113+
const title = formData.get("name");
114+
115+
await new Promise((resolve) => setTimeout(resolve, 1000));
116+
return [...(previousState || []), title];
117+
},
118+
null
119+
);
120+
121+
return (
122+
<form action={submitAction}>
123+
<input type="text" name="name" />
124+
<p>posts: {isPending ? "loading" : (state || []).join(",")}</p>
125+
<SubmitButton />
126+
</form>
127+
);
128+
}
129+
```
130+
- Actions: useOptimistic
131+
```javascript
132+
const updateName = (name) => {
133+
return new Promise((resolve, reject) => {
134+
setTimeout(() => {
135+
resolve(`${name} finished`);
136+
}, 1000);
137+
});
138+
};
139+
function SubmitButton() {
140+
const { pending } = useFormStatus();
141+
142+
return (
143+
<div className="form_item">
144+
<button className="primary" type="submit" disabled={pending}>
145+
{pending ? "Submitting..." : "Submit"}
146+
</button>
147+
</div>
148+
);
149+
}
150+
151+
function ChangeName({ currentName, onUpdateName }) {
152+
const [optimisticName, setOptimisticName] = useOptimistic(currentName);
153+
154+
const submitAction = async (formData) => {
155+
const newName = formData.get("name");
156+
setOptimisticName(newName);
157+
const updatedName = await updateName(newName);
158+
onUpdateName(updatedName);
159+
};
160+
161+
return (
162+
<form action={submitAction}>
163+
<p>Your name is: {optimisticName}</p>
164+
<p>
165+
<label>Change Name:</label>
166+
<input
167+
type="text"
168+
name="name"
169+
disabled={currentName !== optimisticName}
170+
/>
171+
</p>
172+
<SubmitButton />
173+
</form>
174+
);
175+
}
176+
177+
export default function App() {
178+
const [currentName, updateName] = useState("");
179+
180+
return <ChangeName currentName={currentName} onUpdateName={updateName} />;
181+
}
182+
183+
```
184+
- Actions:use
185+
186+
使用 Promise 及 Context 示例
187+
188+
```javascript
189+
function Comments({ commentsPromise }) {
190+
// `use` will suspend until the promise resolves.
191+
const comments = use(commentsPromise);
192+
return comments.map((comment) => <p key={comment.id}>{comment.comment}</p>);
193+
}
194+
195+
function Page({ commentsPromise }) {
196+
// When `use` suspends in Comments,
197+
// this Suspense boundary will be shown.
198+
return (
199+
<Suspense fallback={<div>Loading...</div>}>
200+
<Comments commentsPromise={commentsPromise} />
201+
</Suspense>
202+
);
203+
}
204+
205+
const themeContext = createContext({ color: "light" });
206+
207+
export default function App() {
208+
const theme = use(themeContext);
209+
210+
console.log("theme color:", theme?.color);
211+
212+
const commentsPromise = new Promise((resolve) => {
213+
setTimeout(() => {
214+
resolve([
215+
{ id: 1, comment: "hello 1" },
216+
{ id: 2, comment: "hello 2" },
217+
{ id: 3, comment: "hello 3" },
218+
{ id: 4, comment: "hello 4" },
219+
]);
220+
}, 1000);
221+
});
222+
223+
return <Page commentsPromise={commentsPromise} />;
224+
}
225+
```
226+
227+
### Improvements
228+
229+
- ref as a prop
230+
231+
> 移除了 forwardRef 的写法
232+
233+
```javascript
234+
function MyInput({placeholder, ref}) {
235+
return <input placeholder={placeholder} ref={ref} />
236+
}
237+
238+
//...
239+
<MyInput ref={ref} />
240+
```
241+
242+
- \<Context\> as a provider
243+
244+
> Context 替代了 <del>Context.Provider</del>「已弃用」
245+
246+
```javascript
247+
const ThemeContext = createContext('');
248+
249+
function App({children}) {
250+
return (
251+
<ThemeContext value="dark">
252+
{children}
253+
</ThemeContext>
254+
);
255+
}
256+
```
257+
258+
- Cleanup functions for refs
259+
260+
```javascript
261+
<input
262+
ref={(ref) => {
263+
// ref created
264+
265+
// NEW: return a cleanup function to reset
266+
// the ref when element is removed from DOM.
267+
return () => {
268+
// ref cleanup
269+
};
270+
}}
271+
/>
272+
273+
// 停止使用 隐式返回,因为引入了 ref 清理函数,需改为下面写法
274+
- <div ref={current => (instance = current)} />
275+
+ <div ref={current => {instance = current}} />
276+
```
277+
278+
- useDeferredValue initial value
279+
280+
当提供 initialValue 时,useDeferredValue 会将其作为组件初始渲染的值返回,并使用返回的 deferredValue 在后台安排重新渲染。
281+
```javascript
282+
function Search({deferredValue}) {
283+
// 首次渲染的值为 空字符串
284+
// 然后使用新得到的 deferredValue 安排重新渲染
285+
const value = useDeferredValue(deferredValue, '');
286+
287+
return (
288+
<Results query={value} />
289+
);
290+
}
291+
```
292+
6293
## 15 版本特点
7294
8295
React 15 的架构分为两层

0 commit comments

Comments
 (0)