React 进阶阶段学习计划
目标
掌握自定义Hooks的创建和使用。
深入理解上下文(Context)和Redux的高级用法。
学会服务端渲染(SSR)。
深入探讨性能优化技巧。
学习内容
自定义Hooks
创建和使用自定义Hooks
自定义Hooks:用于提取组件逻辑,使代码更加模块化和复用。
示例:
// useFetch.js
import { useState, useEffect } from 'react';
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchData() {
try {
const response = await fetch(url);
const json = await response.json();
setData(json);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
}
fetchData();
}, [url]);
return { data, loading, error };
}
export default useFetch;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// App.js
import React from 'react';
import useFetch from './useFetch';
function App() {
const { data, loading, error } = useFetch('https://jsonplaceholder.typicode.com/posts');
if (loading) return
if (error) return
return (
Data from API
{data.map(item => (
- {item.title}
))}
);
}
export default App;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
上下文(Context)和Redux的高级用法
上下文(Context)的高级用法
Context Consumer:用于在函数组件中消费Context。
示例:
// ThemeContext.js
import React, { createContext, useContext, useState } from 'react';
const ThemeContext = createContext();
// 提供者组件
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
};
return (
{children}
);
}
// 消费者组件
function ThemedButton() {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
);
}
// App.js
import React from 'react';
import ThemeProvider from './ThemeProvider';
import ThemedButton from './ThemedButton';
function App() {
return (
);
}
export default App;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
Redux的高级用法
Redux Toolkit:简化Redux的开发流程。
安装:
npm install @reduxjs/toolkit react-redux
1
示例:
// store.js
import { configureStore, createSlice } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
},
});
const store = configureStore({
reducer: {
counter: counterSlice.reducer,
},
});
export const { increment, decrement } = counterSlice.actions;
export default store;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// App.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement } from './store';
import { Provider } from 'react-redux';
import store from './store';
function Counter() {
const count = useSelector((state) => state.counter.value);
const dispatch = useDispatch();
return (
Count: {count}
);
}
function App() {
return (
);
}
export default App;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
服务端渲染(SSR)
Next.js
Next.js:一个流行的React框架,支持服务端渲染。
安装:
npx create-next-app@latest my-app
cd my-app
npm run dev
1
2
3
示例:
// pages/index.js
import { useState } from 'react';
export default function Home() {
const [count, setCount] = useState(0);
return (
Welcome to Next.js!
Count: {count}
);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// pages/api/hello.js
export default function handler(req, res) {
res.status(200).json({ name: 'John Doe' });
}
1
2
3
4
性能优化的深入探讨
使用React Profiler
React Profiler:用于分析组件的渲染性能。
启用Profiler:
import React, { Profiler } from 'react';
function onRender(id, phase, actualDuration, baseDuration, startTime, commitTime) {
console.log({ id, phase, actualDuration, baseDuration, startTime, commitTime });
}
function App() {
return (
React Profiler Example
{/ 其他组件 /}
);
}
export default App;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
使用React.memo和PureComponent
React.memo:用于优化函数组件的性能。
PureComponent:用于优化类组件的性能。
示例:
// MyComponent.js
import React, { PureComponent } from 'react';
class MyComponent extends PureComponent {
render() {
return
}
}
export default MyComponent;
1
2
3
4
5
6
7
8
9
10
// MyFunctionComponent.js
import React from 'react';
const MyFunctionComponent = React.memo(({ value }) => {
return
});
export default MyFunctionComponent;
1
2
3
4
5
6
7
8
实践项目
社交媒体应用
创建项目:
npx create-next-app@latest social-media-app
cd social-media-app
npm run dev
1
2
3
创建组件:
PostList.js:显示帖子列表
import React, { useState, useEffect } from 'react';
import axios from 'axios';
function PostList() {
const [posts, setPosts] = useState([]);
useEffect(() => {
axios.get('https://jsonplaceholder.typicode.com/posts')
.then(response => {
setPosts(response.data);
})
.catch(error => {
console.error('Error fetching posts:', error);
});
}, []);
return (
{posts.map(post => (
{post.title}
{post.body}
))}
);
}
export default PostList;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
App.js:主组件
import React from 'react';
import PostList from '../components/PostList';
function Home() {
return (
Social Media App
);
}
export default Home;
1
2
3
4
5
6
7
8
9
10
11
12
13
博客管理系统
创建项目:
npx create-react-app blog-management --template typescript
cd blog-management
npm start
1
2
3
安装axios:
npm install axios
1
创建组件:
PostForm.tsx:添加和编辑帖子的表单
import React, { useState } from 'react';
import axios from 'axios';
interface Post {
id?: number;
title: string;
content: string;
}
interface PostFormProps {
initialPost?: Post;
onSubmit: (post: Post) => void;
}
const PostForm: React.FC = ({ initialPost, onSubmit }) => {
const [post, setPost] = useState({
id: initialPost?.id,
title: initialPost?.title || '',
content: initialPost?.content || '',
});
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
onSubmit(post);
setPost({ title: '', content: '' });
};
return (
setPost({ ...post, title: e.target.value })}
placeholder="Title"
/>
setPost({ ...post, content: e.target.value })}<br> placeholder="Content"<br> /><br> <button type="submit">Submit</button><br> </form><br> );<br>};</p> <p>export default PostForm;</p> <p>1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br>23<br>24<br>25<br>26<br>27<br>28<br>29<br>30<br>31<br>32<br>33<br>34<br>35<br>36<br>37<br>38<br>39<br>40<br>41<br>42<br>43<br>44<br>45<br>46<br>PostList.tsx:显示帖子列表</p> <p>import React, { useState, useEffect } from 'react';<br>import axios from 'axios';<br>import PostForm from './PostForm';</p> <p>interface Post {<br> id: number;<br> title: string;<br> content: string;<br>}</p> <p>const PostList: React.FC = () => {<br> const [posts, setPosts] = useState<Post[]>([]);<br> const [editingPost, setEditingPost] = useState<Post | null>(null);</p> <p> useEffect(() => {<br> axios.get<Post[]>('<a href="https://jsonplaceholder.typicode.com/posts">https://jsonplaceholder.typicode.com/posts</a>')<br> .then(response => {<br> setPosts(response.data.slice(0, 10));<br> })<br> .catch(error => {<br> console.error('Error fetching posts:', error);<br> });<br> }, []);</p> <p> const handleEdit = (post: Post) => {<br> setEditingPost(post);<br> };</p> <p> const handleDelete = (postId: number) => {<br> setPosts(posts.filter(post => post.id !== postId));<br> };</p> <p> const handleSave = (post: Post) => {<br> if (post.id) {<br> setPosts(posts.map(p => (p.id === post.id ? post : p)));<br> } else {<br> setPosts([...posts, post]);<br> }<br> setEditingPost(null);<br> };</p> <p> return (<br> <div className="post-list"><br> {editingPost ? (<br> <PostForm initialPost={editingPost} onSubmit={handleSave} /><br> ) : (<br> <PostForm onSubmit={handleSave} /><br> )}<br> <ul><br> {posts.map(post => (<br> <li key={post.id}><br> <h3>{post.title}</h3><br> <p>{post.content}</p><br> <button onClick={() => handleEdit(post)}>Edit</button><br> <button onClick={() => handleDelete(post.id)}>Delete</button><br> </li><br> ))}<br> </ul><br> </div><br> );<br>};</p> <p>export default PostList;</p> <p>1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br>23<br>24<br>25<br>26<br>27<br>28<br>29<br>30<br>31<br>32<br>33<br>34<br>35<br>36<br>37<br>38<br>39<br>40<br>41<br>42<br>43<br>44<br>45<br>46<br>47<br>48<br>49<br>50<br>51<br>52<br>53<br>54<br>55<br>56<br>57<br>58<br>59<br>60<br>61<br>62<br>63<br>App.tsx:主组件</p> <p>import React from 'react';<br>import PostList from './components/PostList';</p> <p>const App: React.FC = () => {<br> return (<br> <div className="App"><br> <h1>Blog Management System</h1><br> <PostList /><br> </div><br> );<br>};</p> <p>export default App;<br>1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9<br>10<br>11<br>12<br>13<br>建议<br>定期回顾:每周花时间回顾本周所学内容,确保知识点牢固掌握。<br>参与社区:加入React相关的论坛、Slack群组或Discord服务器,与其他开发者交流心得。<br>阅读源码:尝试阅读一些复杂的React库的源码,提高代码理解和分析能力。<br>希望这个学习计划能够帮助你系统地学习React进阶技能,并通过实践项目巩固所学知识。祝你学习顺利!</p> <p>你可以将上述Markdown内容复制到任何支持Markdown的编辑器或平台中,以便于查看和使用。</p>