本文主要介绍了 React 的相关知识,包括表单控制、组件通信、副作用管理、自定义 Hook 以及 Hooks 使用规则等内容,并通过一些案例进行了说明,以下是详细总结:
1. React 表单控制
- 受控绑定
import 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
事件,实现表单值与状态的同步。
- 非受控绑定
import 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
)。
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
属性给子组件,子组件接收并渲染的代码。function 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
属性中接收该内容。
- 基础实现
- 父子通信 - 子传父
- 核心思路:子组件调用父组件传递的函数并传递参数。
- 示例代码:子组件通过按钮点击事件调用父组件传递的函数,将数据传递给父组件。
function 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 组件的完整代码。
import { 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 组件的跨层通信代码。
import { 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 等。
基础使用import 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>); }
- 需求示例:在组件渲染完毕后从服务端获取频道列表数据并显示。
import 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
中开启定时器,并在组件卸载时清理定时器的代码。import 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 的通用封装思路。import { useState } from 'react';function useToggle() {// 可复用的逻辑代码const [value, setValue] = useState(true);const toggle = () => setValue(!value);// 哪些状态和回调函数需要在其他组件中使用 returnreturn {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 站评论案例
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 函数封装数据请求的逻辑。
- 把评论中的每一项抽象成一个独立的组件实现渲染。