本文主要介绍了 React 的相关知识,包括表单控制、组件通信、副作用管理、自定义 Hook 以及 Hooks 使用规则等内容,并通过一些案例进行了说明,以下是详细总结:
1. React 表单控制
-
受控绑定
javascriptimport React, { useState } from 'react'; function App() { const [value, setValue] = useState(''); return ( <input type="text" value={value} onChange={e => setValue(e.target.value)} /> ); }
- 概念:使用 React 组件的状态(useState)控制表单的状态。
- 示例代码 :通过
useState
定义表单值状态,在input
组件上绑定value
和onChange
事件,实现表单值与状态的同步。
-
非受控绑定
javascriptimport React, { useRef } from 'react'; function App() { const inputRef = useRef(null); const onChange = () => { console.log(inputRef.current.value); }; return ( <input type="text" ref={inputRef} onChange={onChange} /> ); }
- 概念:通过获取 DOM 的方式获取表单的输入数据。
- 示例代码 :使用
useRef
创建引用,在input
组件上绑定ref
和onChange
事件,通过引用获取表单值。
2. 案例 - B 站评论案例
- 实现手机输入框评论内容并发布评论,涉及 id 处理(如使用
uuid
)和时间处理(如使用day.js
)。
javascript
import React, { useState } from 'react';
import uuid from 'uuid';
import dayjs from 'dayjs';
function CommentComponent() {
const [comment, setComment] = useState('');
const handleSubmit = () => {
const commentId = uuid.v4();
const commentTime = dayjs().format('YYYY-MM-DD HH:mm:ss');
// 这里可以添加发送评论的逻辑,比如调用接口
console.log(`评论内容:${comment},评论ID:${commentId},评论时间:${commentTime}`);
};
return (
<div>
<input
type="text"
value={comment}
onChange={e => setComment(e.target.value)}
/>
<button onClick={handleSubmit}>发布评论</button>
</div>
);
}
3. React 组件通信
-
概念:组件之间的数据传递,根据组件嵌套关系不同有不同通信手段。
-
父子通信 - 父传子
-
基础实现
-
实现步骤 :父组件在子组件标签上绑定属性传递数据,子组件通过
props
接收数据。 -
示例代码 :展示了父组件传递
name
属性给子组件,子组件接收并渲染的代码。javascriptfunction Son(props) { return <div>{props.name}</div>; } function App() { const name = 'this is app name'; return ( <div> <Son name={name}/> </div> ); }
-
-
props 说明
- 可以传递任意合法数据,如数字、字符串等多种类型。
props
是只读对象,子组件只能读取不能直接修改,父组件数据由父组件修改。
-
特殊的 prop - children :当内容嵌套在组件标签内部时,组件会在
children
属性中接收该内容。
-
-
父子通信 - 子传父
-
核心思路:子组件调用父组件传递的函数并传递参数。
-
示例代码 :子组件通过按钮点击事件调用父组件传递的函数,将数据传递给父组件。
javascriptfunction Son({ onGetMsg }) { const sonMsg = 'this is son msg'; return ( <div> {/* 在子组件中执行父组件传递过来的函数 */} <button onClick={() => onGetMsg(sonMsg)}>send</button> </div> ); } function App() { const getMsg = (msg) => console.log(msg); return ( <div> {/* 传递父组件中的函数到子组件 */} <Son onGetMsg={getMsg}/> </div> ); }
-
-
兄弟组件通信
-
实现思路:借助 "状态提升" 机制,通过共同的父组件进行数据传递,即 A 组件先子传父给父组件 App,App 再父传子给 B 组件。
-
示例代码 :展示了 A 组件传递数据给 App,App 再传递给 B 组件的完整代码。
javascriptimport { useState } from "react"; function A({ onGetAName }) { // Son组件中的数据 const name = 'this is A name'; return ( <div> this is A compnent, <button onClick={() => onGetAName(name)}>send</button> </div> ); } function B({ name }) { return ( <div> this is B compnent, {name} </div> ); } function App() { const [name, setName] = useState(''); const getAName = (name) => { setName(name); }; return ( <div> this is App <A onGetAName={getAName} /> <B name={name} /> </div> ); } export default App;
-
-
跨层组件通信
-
实现步骤
- 使用
createContext
创建上下文对象Ctx
。 - 顶层组件(App)通过
Ctx.Provider
提供数据。 - 底层组件(B)通过
useContext
获取数据。
- 使用
-
示例代码 :展示了从 App 到 A 再到 B 组件的跨层通信代码。
javascriptimport { createContext, useContext } from "react"; // 1. createContext方法创建一个上下文对象 const MsgContext = createContext(); function A() { return ( <div> this is A component <B /> </div> ); } function B() { // 3. 在底层组件 通过useContext钩子函数使用数据 const msg = useContext(MsgContext); return ( <div> this is B compnent,{msg} </div> ); } function App() { const msg = 'this is app msg'; return ( <div> {/* 2. 在顶层组件 通过Provider组件提供数据 */} <MsgContext.Provider value={msg}> this is App <A /> </MsgContext.Provider> </div> ); } export default App;
-
4. React 副作用管理 - useEffect
-
概念理解 :用于在 React 组件中创建由渲染本身引起的操作(副作用),如发送 AJAX 请求、更改 DOM 等。
javascriptimport React, { useEffect, useState } from 'react'; function App() { const [data, setData] = useState(null); useEffect(() => { // 这里可以模拟发送请求获取数据 const mockData = { message: '模拟数据' }; setData(mockData); }, []); return ( <div> {data && <div>{data.message}</div>} </div> ); }
基础使用
-
需求示例 :在组件渲染完毕后从服务端获取频道列表数据并显示。
javascriptimport React, { useEffect, useState } from 'react'; function App() { const [data, setData] = useState(null); useEffect(() => { fetch('https://example.com/api/data') .then(response => response.json()) .then(data => setData(data)); }, []); return ( <div> {data && <div>{data.message}</div>} </div> ); }
-
参数说明
- 参数 1 是副作用函数,内部放置要执行的操作。
- 参数 2 是可选的数组(依赖项),影响副作用函数的执行时机,空数组时只在初始渲染后执行一次。
-
-
useEffect 依赖说明
- 无依赖项时,组件初始渲染和更新时执行副作用函数。
- 空数组依赖时,只在初始渲染时执行一次。
- 添加特定依赖项时,组件初始渲染和依赖项变化时执行。
-
清除副作用
-
概念 :清理在
useEffect
中编写的对接组件外部的操作,如组件卸载时清理定时器。 -
示例代码 :展示了在
useEffect
中开启定时器,并在组件卸载时清理定时器的代码。javascriptimport React, { useEffect, useState } from 'react'; function Son() { // 1. 渲染时开启一个定时器 useEffect(() => { const timer = setInterval(() => { console.log('定时器执行中...'); }, 1000); return () => { // 清除副作用(组件卸载时) clearInterval(timer); } }, []); return <div>this is son</div>; } function App() { // 通过条件渲染模拟组件卸载 const [show, setShow] = useState(true); return ( <div> {show && <Son />} <button onClick={() => setShow(false)}>卸载Son组件</button> </div> ); } export default App;
-
5. 自定义 Hook 实现
-
概念 :以
use
打头的函数,用于实现逻辑的封装和复用。 -
示例代码 :展示了一个自定义
useToggle
函数,封装了布尔值切换的逻辑,并在其他组件中使用的代码,同时介绍了自定义 hook 的通用封装思路。javascriptimport { useState } from 'react'; function useToggle() { // 可复用的逻辑代码 const [value, setValue] = useState(true); const toggle = () => setValue(!value); // 哪些状态和回调函数需要在其他组件中使用 return return { value, toggle }; } function App() { const { value, toggle } = useToggle(); return ( <div> {value && <div>this is div</div>} <button onClick={toggle}>toggle</button> </div> ); }
6. React Hooks 使用规则
- 只能在组件中或其他自定义 Hook 函数中调用。
- 只能在组件的顶层调用,不能嵌套在
if
、for
或其他函数中。
7. 案例 - 优化 B 站评论案例
javascript
import React, { useState } from 'react';
import { useEffect } from 'react-hooks';
// 自定义Hook函数封装数据请求逻辑
function useFetchComments() {
const [comments, setComments] = useState([]);
useEffect(() => {
fetch('https://example.com/api/comments')
.then(response => response.json())
.then(data => setComments(data));
}, []);
return comments;
}
function CommentItem({ comment }) {
return <div>{comment.text}</div>;
}
function CommentList() {
const comments = useFetchComments();
return (
<div>
{comments.map(comment => (
<CommentItem key={comment.id} comment={comment} />
))}
</div>
);
}
function App() {
return (
<div>
<CommentList />
</div>
);
}
- 使用请求接口的方式获取评论列表并渲染。
- 使用自定义 Hook 函数封装数据请求的逻辑。
- 把评论中的每一项抽象成一个独立的组件实现渲染。