react 知识点汇总(非常全面)

React 是一个用于构建用户界面的 JavaScript 库,由 Facebook 开发并维护。它的核心理念是“组件化”,即将用户界面拆分为可重用的组件。

React 的组件通常使用 JSX(JavaScript XML)。JSX 是一种 JavaScript 语法扩展,允许开发者在 JavaScript 代码中编写类似 HTML 的结构。

1、初识react

1.1 常用命令

首先安装 Nodejs,然后执行下面命令安装 react

npm i -g create-react-app
create-react-app myreact # 创建react项目npm start # 在项目中输入,启动项目

1.2 项目结构

项目创建后有很多文件,一般我们只需保留下面的就行.

  • index.html:应用的主 HTML 文件,React 应用的根组件通常挂载在此文件中的一个
    元素上。
  • index.css:全局样式文件。
  • index.js:应用的入口文件,负责渲染根组件并将其挂载到 index.html 中的 DOM。
  • package.json: 包含项目的元数据(如名称、版本、描述等)、依赖包列表和脚本命令(如 startbuildtest)。
my-app/
├── node_modules/
├── public/
│   ├── favicon.ico
|   ├── index.html
├── src/
│   ├── index.css
│   ├── index.js
├── .gitignore
├── package.json
├── README.md
└── yarn.lock / package-lock.json

2、基本知识点

1. extends Component

在 React 中,extends Component 是用来创建类组件的方式。React 的类组件通过继承 React.Component 来获得组件的基本功能,如状态管理和生命周期方法。以下是一个简单的例子:

import React, { Component } from 'react';class MyComponent extends Component {render() {return <h1>Hello, World!</h1>;}
}
  • Component:是 React 提供的基类,包含了生命周期方法(如 componentDidMountcomponentDidUpdate 等)和其他基本功能。

  • render 方法:每个类组件必须实现的一个方法,用于描述 UI 如何渲染。每当组件的 stateprops 更新时,render 方法会被调用。

    render() {return (<div><h1>Hello, {this.props.name}!</h1></div>);
    }
    
    • 返回值render 方法可以返回一个单一的元素、多个元素(需要用一个父元素包裹)或者 null

2. React.Fragment

React.Fragment 是一个用于分组多个子元素而不添加额外 DOM 节点的工具。通常,React 要求每个组件必须返回一个单一的根元素,使用 Fragment 可以解决这个问题。示例:

import React from 'react';class MyComponent extends Component {render() {return (<React.Fragment><h1>Title</h1><p>Some content.</p></React.Fragment>);}
}
  • 语法简化:可以用 <></> 来简化 Fragment 的使用:

3. className

在 React 中,使用 className 属性来指定一个或多个 CSS 类,而不是使用 HTML 的 class 属性。这是因为 class 是 JavaScript 中的保留关键字,React 采用 className 来避免冲突。

示例:

function MyComponent() {return <div className="my-class">Hello, World!</div>;
}
.my-class {color: blue;font-size: 20px;
}
动态类名
function MyComponent({ isActive }) {return (<div className={`my-class ${isActive ? 'active' : ''}`}>Hello, World!</div>);
}

在这个例子中,如果 isActivetruediv 将具有 active 类。

4. {} 的用法

在 JSX 中,{} 用于表示 JavaScript 表达式。你可以在其中嵌入变量、函数调用和其他表达式。

示例:

const name = "Alice";function Greeting() {return <h1>Hello, {name}!</h1>; // 使用 {} 插入变量
}

5 jsx 中的 css

1. 基本语法

在 JSX 中,内联样式需要使用 JavaScript 对象的形式定义。具体来说:

  • 样式属性使用驼峰命名法(camelCase)。
  • 属性值通常为字符串或数字(需要附加单位时,使用字符串)。
1.1 示例代码
const MyComponent = () => {const style = {color: 'blue',backgroundColor: 'lightgray',padding: '10px',fontSize: '16px',border: '1px solid black'};return <div style={style}>这是一个内联样式的组件</div>;
};

在这个示例中,我们定义了一个样式对象 style,并将其应用到 <div> 元素中。

2. 动态样式

内联样式的一个主要优势是可以很容易地根据组件的状态或属性动态更新样式。例如,可以根据 state 的值来改变样式:

import React, { useState } from 'react';const DynamicStyleComponent = () => {const [isActive, setIsActive] = useState(false);const style = {color: isActive ? 'white' : 'black',backgroundColor: isActive ? 'blue' : 'gray',padding: '10px',cursor: 'pointer'};return (<div style={style} onClick={() => setIsActive(!isActive)}>{isActive ? '激活状态' : '非激活状态'}</div>);
};

在这个示例中,点击 <div> 会切换其状态,从而改变文字和背景颜色。

3. 优缺点
优点
  • 简单直接:可以快速应用样式,尤其是动态样式时。
  • 无类名冲突:因为样式是局部的,不会受到其他样式的影响。
缺点
  • 不可复用:无法将样式应用于多个组件,难以维护。
  • 性能问题:每次渲染都会创建新的对象,可能会影响性能,特别是在频繁更新的组件中。
  • 不支持伪类和媒体查询:无法使用 CSS 的伪类(如 :hover)和媒体查询,限制了样式的灵活性。

3、Componets 写法

1. React 组件的基本概念

React 组件是构成 React 应用的基本单元。它们可以是类组件或函数组件。类组件使用 ES6 类来定义,而函数组件则是简单的 JavaScript 函数。

1.1 类组件

类组件通常用于需要管理状态或使用生命周期方法的场景。

import React, { Component } from 'react';class MyComponent extends Component {// 构造函数用于初始化 stateconstructor(props) {super(props);this.state = {count: 0};}// 上面 constructor 这块的代码可以只写 state {count : 0}, // 在类组件中,可以直接在类的主体中定义 state,而不必在构造函数中初始化。// 这种语法会自动将 state 绑定到实例上,因此不需要显式调用 super(props)。// 增加 count 的方法increment = () => {this.setState({ count: this.state.count + 1 });};render() {return (<div><h1>{this.state.count}</h1><button onClick={this.increment}>增加</button></div>);}
}export default MyComponent;
1.2 函数组件

函数组件是无状态的,可以使用 React Hooks 来管理状态和副作用。

import React, { useState } from 'react';const MyComponent = () => {const [count, setCount] = useState(0); // useState Hookconst increment = () => {setCount(count + 1);};return (<div><h1>{count}</h1><button onClick={increment}>增加</button></div>);
};export default MyComponent;

2. State 的管理

state 是组件的本地状态,用于存储组件的动态数据。当状态改变时,React 会自动重新渲染组件。

2.1 设置初始状态

在类组件中,初始状态通常在构造函数中定义;在函数组件中,可以使用 useState Hook。

2.2 修改状态

使用 this.setState(类组件)或状态更新函数(函数组件)来更新状态。重要的是,状态更新是异步的。

// 类组件
this.setState({ key: value });// 函数组件
setCount(newCount);

3. 遍历生成元素

在状态中存储一个数组,然后通过 .map() 方法遍历生成多个元素。

3.1 类组件示例
class ListComponent extends Component {constructor(props) {super(props);this.state = {items: ['苹果', '香蕉', '橙子']};}render() {return (<ul>{this.state.items.map((item, index) => (<li key={index}>{item}</li>))}</ul>);}
}
3.2 函数组件示例
const ListComponent = () => {const [items, setItems] = useState(['苹果', '香蕉', '橙子']);return (<ul>{items.map((item, index) => (<li key={index}>{item}</li>))}</ul>);
};

4. 函数传参

4.1 传递参数 e
class MyComponent extends Component {handleClick = (e) => {console.log(e.target);};render() {return (<button onClick={this.handleClick}>	// 传递参数 eClick me</button>);}
}
4.2 传递自定义参数
class MyComponent extends Component {handleClick = (param) => {console.log('Button clicked!', param);};render() {return (<button onClick={() => this.handleClick('Hello')}>	// 传递自定义参数Click me</button>);}
}
4.3 传递参数 e 和 自定义参数
class MyComponent extends Component {handleClick = (param, e) => {console.log('Button clicked!', param);};render() {return (<button onClick={(e) => this.handleClick('Hello', e)}>	// 传递参数Click me</button>);}
}

5. 添加、删除和更新状态

可以通过按钮或其他交互方式来添加、删除或更新状态中的元素。

5.1 添加元素
// 在类组件中
addItem = () => {this.setState(prevState => ({items: [...prevState.items, '新水果']}));
};// 在函数组件中
const addItem = () => {setItems([...items, '新水果']);
};
5.2 删除元素
// 在类组件中
removeItem = index => {this.setState(prevState => ({items: prevState.items.filter((_, i) => i !== index)}));
};// 在函数组件中
const removeItem = index => {setItems(items.filter((_, i) => i !== index));
};

6. 受控表单绑定

import React, { useState } from 'react';function ControlledForm() {const [name, setName] = useState('');const [email, setEmail] = useState('');const handleSubmit = (e) => {e.preventDefault();alert(`Name: ${name}, Email: ${email}`);};return (<form onSubmit={handleSubmit}><div><label>Name:<inputtype="text"value={name}	// 把 name 赋值给valueonChange={(e) => setName(e.target.value)}		// name 绑定上target.value/></label></div><div><label>Email:<inputtype="email"value={email}onChange={(e) => setEmail(e.target.value)}/></label></div><button type="submit">Submit</button></form>);
}export default ControlledForm;

7. 获取dom元素

1. 函数组件

可以通过 useRef 创建 refs:

import React, { useRef } from 'react';function FocusInput() {const inputRef = useRef(null);	const handleFocus = () => {inputRef.current.focus(); // 获取到的 DOM 元素调用 focus 方法};return (<div><input type="text" ref={inputRef} /><button onClick={handleFocus}>Focus the input</button></div>);
}export default FocusInput;
  • useRef: 创建一个 ref,用于存储对 DOM 元素的引用。
  • ref 属性: 将 ref 赋值给要获取的元素,例如 <input>
  • 访问 DOM 元素: 通过 inputRef.current 来访问 DOM 元素。
2. 类组件

可以通过 React.createRef() 创建 refs:

import React, { Component } from 'react';class FocusInput extends Component {constructor(props) {super(props);this.inputRef = React.createRef();}handleFocus = () => {this.inputRef.current.focus();};render() {return (<div><input type="text" ref={this.inputRef} /><button onClick={this.handleFocus}>Focus the input</button></div>);}
}export default FocusInput;

4、组件之间传递数据

子组件接收到的 props 是不可变的。如果需要修改 props 中的数据,应该通过父组件来管理状态并传递更新的值。

1 - 4 都是 父传子, 5 是 子传父

1. 传递常见数据类型(类组件写法)

在父组件的 state 中存储基本数据类型,并通过 props 传递给子组件。

父组件

import React, { Component } from 'react';
import ChildComponent from './ChildComponent';class ParentComponent extends Component {state = {// 基本数据类型message: 'Hello from Parent!',numberValue: 42,boolValue: true,user: {	// 对象name: 'Alice',age: 30,},};handleAlert = () => {	// 方法alert('Hello from Parent!');};updateBoolValue = () => {this.setState(prevState => ({ boolValue: !prevState.boolValue }));};render() {return (<div><h1>Parent Component</h1><ChildComponentmessage={this.state.message}number={this.state.numberValue}isTrue={this.state.boolValue}user={this.state.user}	// 对象showAlert={this.handleAlert}	// 方法/><button onClick={this.updateBoolValue}>Toggle Boolean</button></div>);}
}export default ParentComponent;

子组件

import React, { Component } from 'react';class ChildComponent extends Component {render() {return (<div><h2>Child Component</h2><p>{this.props.message}</p><p>Number: {this.props.number}</p><p>Boolean: {this.props.isTrue ? 'True' : 'False'}</p><ChildComponent user={this.state.user} />	// 对象</div>);}
}export default ChildComponent;

2. 传递常见数据类型(函数组件写法)

父组件

import React, { useState } from 'react';
import ChildComponent from './ChildComponent';const ParentComponent = () => {const [message] = useState('Hello from Parent!');const [numberValue] = useState(42);const [boolValue, setBoolValue] = useState(true);const [user] = useState({name: 'Alice',age: 30,});const handleAlert = () => {alert('Hello from Parent!');};const updateBoolValue = () => {setBoolValue(prev => !prev);};return (<div><h1>Parent Component</h1><ChildComponentmessage={message}number={numberValue}isTrue={boolValue}user={user}showAlert={handleAlert}/><button onClick={updateBoolValue}>Toggle Boolean</button></div>);
};export default ParentComponent;

子组件

import React from 'react';const ChildComponent = ({ message, number, isTrue, user }) => {return (<div><h2>Child Component</h2><p>{message}</p><p>Number: {number}</p><p>Boolean: {isTrue ? 'True' : 'False'}</p><p>User: {user.name}, Age: {user.age}</p> {/* 对象 */}</div>);
};export default ChildComponent;

说明

  • 使用 useState 来管理状态。
  • 通过解构 props 直接在函数参数中获取需要的值。
  • 保持功能和逻辑不变,实现了相同的父子组件传值。

3. 传递多个 HTML 结构(类组件)

父组件将多个 JSX 元素传递给子组件,通过 props.children 访问这些元素。

import React, { Component } from 'react';
import ChildComponent from './ChildComponent';class ParentComponent extends Component {render() {return (<div><h1>Parent Component</h1><ChildComponent>	//  把 html 写在组件子组件当中<p>This is the first custom content!</p><p>This is the second custom content!</p><h3>This is a header as custom content!</h3></ChildComponent></div>);}
}export default ParentComponent;

子组件

在子组件中,我们可以通过 React.Children.map 或者 this.props.children 分别处理传递过来的多个元素。

import React, { Component } from 'react';class ChildComponent extends Component {render() {return (<div><h2>Child Component</h2>	// children数组中包含了父组件传递的 html{React.Children.map(this.props.children, (child, index) => (<div key={index}>{child}</div>))}</div>);}
}export default ChildComponent;

4. 传递多个 HTML 结构(函数组件)

父组件

import React from 'react';
import ChildComponent from './ChildComponent';const ParentComponent = () => {return (<div><h1>Parent Component</h1><ChildComponent><p>This is the first custom content!</p><p>This is the second custom content!</p><h3>This is a header as custom content!</h3></ChildComponent></div>);
};export default ParentComponent;

子组件

import React from 'react';const ChildComponent = ({ children }) => {return (<div><h2>Child Component</h2>{React.Children.map(children, (child, index) => (<div key={index}>{child}</div>))}</div>);
};export default ChildComponent;

说明

  • 父组件: 使用函数组件,并将多个 JSX 元素作为子组件的内容传递。
  • 子组件: 通过解构 props 获取 children,并使用 React.Children.map 迭代处理每个子元素。

5. 子传父

父组件

import React, { useState } from 'react';
import ChildComponent from './ChildComponent';const ParentComponent = () => {const [dataFromChild, setDataFromChild] = useState('');const handleDataChange = (data) => {setDataFromChild(data);};return (<div><h1>Parent Component</h1><p>Data from Child: {dataFromChild}</p><ChildComponent onDataChange={handleDataChange} /></div>);
};export default ParentComponent;

子组件

import React from 'react';const ChildComponent = ({ onDataChange }) => {const sendDataToParent = () => {const data = 'Hello from Child!';onDataChange(data); // 调用父组件传来的函数};return (<div><h2>Child Component</h2><button onClick={sendDataToParent}>Send Data to Parent</button></div>);
};export default ChildComponent;

说明

  1. 父组件: ParentComponent 使用 useState 来存储从子组件接收到的数据,并定义一个 handleDataChange 函数来更新状态。
  2. 子组件: ChildComponent 接收 onDataChange 函数作为 prop,点击按钮时调用该函数将数据发送给父组件。

5、生命周期

  • 挂载阶段

    • constructor()
    • render()
    • componentDidMount()
  • 更新阶段

    • getDerivedStateFromProps()
    • shouldComponentUpdate()
    • render()
    • componentDidUpdate()
  • 卸载阶段

    • componentWillUnmount()

1. 挂载(Mount)

当组件被创建并插入到 DOM 中时,进入挂载阶段。执行顺序如下:

  1. constructor():构造函数用于初始化状态和绑定方法。
  2. render():返回要渲染的 JSX,决定组件的结构。
  3. componentDidMount():组件挂载后调用,适合进行 API 请求或添加事件监听。

2. 更新(Update)

当组件的状态或属性发生变化时,组件会重新渲染,进入更新阶段。执行顺序如下:

  1. render():重新渲染组件。
  2. getDerivedStateFromProps(nextProps, prevState):在渲染前调用,可以根据新 props 更新 state。
  3. shouldComponentUpdate(nextProps, nextState):用于控制组件是否重新渲染,返回 truefalse
  4. componentDidUpdate(prevProps, prevState):组件更新后调用,可以根据上一个状态或属性执行副作用。

3. 卸载(Unmount)

当组件从 DOM 中移除时,进入卸载阶段。执行顺序如下:

  1. componentWillUnmount():组件卸载前调用,适合清理资源(如取消网络请求或移除事件监听)。

4. 使用 Hook 的方式

在函数组件中,可以使用 Hook 来实现类似的生命周期效果:

  • useEffect:相当于 componentDidMountcomponentDidUpdate,可以用于处理副作用。
import React, { useEffect, useState } from 'react';const MyComponent = () => {const [count, setCount] = useState(0);useEffect(() => {// 组件挂载时执行console.log('Component mounted');// 组件更新时执行return () => {// 组件卸载时清理console.log('Component unmounted');};}, [count]); // 依赖数组,count 变化时执行return (<div><p>Count: {count}</p><button onClick={() => setCount(count + 1)}>Increment</button></div>);
};

6、 路由

1. 基础概念

路由(Routing):在单页应用(SPA)中,路由用于管理不同视图或页面之间的导航。当用户点击链接或按钮时,路由会拦截这些操作,并根据 URL 的变化加载相应的组件,而不需要重新加载整个页面。

React Router:这是最流行的 React 路由库,它提供了灵活的路由功能。React Router 通过组件化的方式来定义和管理路由。

2. 常用组件

React Router 提供了几个核心组件,下面是一些常用的组件及其用途:

  • BrowserRouter:这个组件提供了基于 HTML5 的历史记录的路由。它通常包裹在应用的根组件外部。

    import { BrowserRouter } from 'react-router-dom';function App() {return (<BrowserRouter>{/* 其他组件 */}</BrowserRouter>);
    }
    
  • Route:用于定义路由的组件。它接受 path 属性来指定匹配的 URL,以及 element 属性来指定渲染的组件。

    import { Route } from 'react-router-dom';<Route path="/about" element={<About />} />
    
  • Routes:用来包裹多个 Route 组件,确保只有一个匹配的路由被渲染。

    import { Routes } from 'react-router-dom';<Routes><Route path="/" element={<Home />} /><Route path="/about" element={<About />} />
    </Routes>
    
  • Link:用于在应用中创建导航链接的组件。它类似于 HTML 的 <a> 标签,但使用的是客户端路由。

    import { Link } from 'react-router-dom';<Link to="/about">About</Link>
    
  • Navigate:用于在组件中进行重定向。

    import { Navigate } from 'react-router-dom';<Navigate to="/home" />
    

3. 路由配置

配置路由通常涉及创建一个路由表,定义各个路由及其对应的组件。以下是一个简单的示例,展示如何在 React 应用中配置路由。

import React from 'react';
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';// 导入页面组件
import Home from './Home';
import About from './About';
import NotFound from './NotFound';function App() {return (<BrowserRouter><nav><Link to="/">Home</Link><Link to="/about">About</Link></nav><Routes><Route path="/" element={<Home />} /><Route path="/about" element={<About />} />{/* 404 页面 */}<Route path="*" element={<NotFound />} /></Routes></BrowserRouter>);
}export default App;

4. 嵌套路由 及 路由守卫、404

嵌套路由允许你在某个父路由的组件内部定义子路由。这样,你可以在父路由的页面中渲染子路由对应的内容。

import { Routes, Route, Link } from 'react-router-dom';function Users() {return (<div><h2>Users</h2><Link to="1">User 1</Link><Link to="2">User 2</Link><Routes><Route path=":userId" element={<UserProfile />} /></Routes></div>);
}function UserProfile() {const { userId } = useParams();return <h3>User Profile for User ID: {userId}</h3>;
}

路由守卫

路由保护可以确保只有特定条件下(例如用户登录后)才能访问某些路由。可以通过创建一个高阶组件(HOC)来实现。

function ProtectedRoute({ element, isAuthenticated }) {return isAuthenticated ? element : <Navigate to="/login" />;
}// 使用
<Routes><Route path="/dashboard" element={<ProtectedRoute element={<Dashboard />} isAuthenticated={isLoggedIn} />} />
</Routes>

404 页面处理

可以使用通配符路由 * 来处理未匹配的路径,并显示 404 页面。

<Route path="*" element={<NotFound />} />

5. 动态路由(match)

动态路由允许你在路径中使用参数,这样可以在 URL 中捕获动态值。例如,展示用户信息的页面。

<Route path="/users/:userId" element={<UserProfile />} />
类组件中

使用 URL 参数,可以使用 withRouter 高阶组件来获取路由的 props,包括 matchlocationhistory 对象。

使用 withRouter 获取 URL 参数

import React from 'react';
import { withRouter } from 'react-router-dom';class UserProfile extends React.Component {render() {// 从 props 中获取 match 对象const { match } = this.props;const userId = match.params.userId; // 获取 URL 参数return <div>User ID: {userId}</div>;}
}// 使用 withRouter 将 UserProfile 包装起来
export default withRouter(UserProfile);

关键点

  • withRouter 是一个高阶组件,它将路由的相关信息作为 props 传递给被包装的组件。
  • match.params 中包含了 URL 中的动态参数,像这里的 userId

确保在路由配置中使用 UserProfile 组件时,像这样设置路由:

<Route path="/users/:userId" element={<UserProfile />} />
函数组件

直接使用 useParams 来获取 URL 参数:

import { useParams } from 'react-router-dom';function UserProfile() {const { userId } = useParams();return <div>User ID: {userId}</div>;
}

6. 获取 修改 查询字符串(location)

https://example.com/users?userId=123&userName=Alice

1. 类组件获取查询字符串参数

在类组件中,我们通常使用 withRouter 高阶组件来访问路由相关的信息,包括查询字符串。

示例代码

import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';class QueryParamsClassComponent extends Component {render() {const { location } = this.props; // 从 props 中获取 location 对象const searchParams = new URLSearchParams(location.search); // 创建 URLSearchParams 对象// 获取具体的参数const userId = searchParams.get('userId'); // 获取 userId 参数const name = searchParams.get('name'); // 获取 name 参数// searchParams。set('userId', '456'); // 修改或添加 userId 参数// searchParams.set('name', 'Alice'); // 修改或添加 name 参数return (<div><h1>Query Parameters</h1><p>User ID: {userId}</p><p>Name: {name}</p></div>);}
}export default withRouter(QueryParamsClassComponent); // 使用 withRouter 包裹类组件

代码解析

  1. 引入 withRouter:首先需要引入 withRouter,它使得组件可以访问路由的 props。
  2. 访问 location 对象:在 render 方法中,从 this.props 中获取 location 对象。
  3. 使用 URLSearchParams
    • new URLSearchParams(location.search) 创建一个 URLSearchParams 对象,location.search 包含查询字符串(包括 ?)。
    • 通过 get 方法提取具体的参数值,例如 userIdname
  4. 渲染参数:在组件的 JSX 中渲染这些参数。
2. 函数组件获取查询字符串参数

在函数组件中,我们可以使用 useLocation Hook 来获取路由信息,包括查询字符串。

示例代码

import React from 'react';
import { useLocation } from 'react-router-dom';const QueryParamsFunctionComponent = () => {const location = useLocation(); // 使用 useLocation 获取 location 对象const searchParams = new URLSearchParams(location.search); // 创建 URLSearchParams 对象// 获取具体的参数const userId = searchParams.get('userId'); // 获取 userId 参数const name = searchParams.get('name'); // 获取 name 参数//searchParams.get('userId'); // 获取 userId 参数//searchParams.get('name'); // 获取 name 参数return (<div><h1>Query Parameters</h1><p>User ID: {userId}</p><p>Name: {name}</p></div>);
};export default QueryParamsFunctionComponent; // 直接导出函数组件

代码解析

  1. 引入 useLocation:引入 useLocation Hook。
  2. 调用 useLocation:在函数组件中调用 useLocation(),它返回当前路由的 location 对象。
  3. 使用 URLSearchParams
    • new URLSearchParams(location.search) 创建一个 URLSearchParams 对象,用于解析查询字符串。
    • 使用 get 方法提取需要的参数值。
  4. 渲染参数:在组件的 JSX 中渲染这些参数。

7、编程导航 history

1. history 对象的概念
  • 历史记录history 对象是一个 JavaScript 对象,它表示浏览器的会话历史。每当用户访问一个新的 URL 时,浏览器会将该 URL 添加到历史记录中。
  • 导航:通过 history 对象,你可以编程式地导航到不同的页面,而不是仅仅依赖于用户点击链接。
2. history 对象的常用方法

history 对象提供了多种方法来处理导航和历史记录。以下是一些常用的方法:

push(path, [state])

  • 功能:在历史记录栈中添加一个新的条目,导航到指定的路径。
  • 参数
    • path:要导航到的路径。
    • state(可选):与新路径关联的状态对象,这个对象可以在目标页面通过 location.state 访问。

示例

this.props.history.push('/home'); // 导航到 /home
this.props.history.push('/profile', { from: 'home' }); // 导航到 /profile,并传递状态

replace(path, [state])

  • 功能:替换当前的历史记录条目,导航到指定的路径,而不是添加一个新的条目。
  • 参数:同 push 方法。

示例

this.props.history.replace('/login'); // 用 /login 替换当前的历史条目

go(n)

  • 功能:根据历史记录栈中的位置导航。
  • 参数
    • n:要导航的相对位置(正数表示向前,负数表示向后)。

示例

this.props.history.go(-1); // 返回到上一页
this.props.history.go(2); // 前进两页

goBack() 返回到上一页,等同于 go(-1)

goForward() 前进到下一页,等同于 go(1)

3. 在 React Router 中使用 history

在 React Router 中,history 对象通常是通过 withRouter 高阶组件或在函数组件中通过 useNavigateuseLocation Hook 访问的。

类组件使用 withRouter

import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';class MyComponent extends Component {handleNavigation = () => {this.props.history.push('/home'); // 使用 history 导航};render() {return <button onClick={this.handleNavigation}>Go to Home</button>;}
}export default withRouter(MyComponent); // 使用 withRouter 包裹组件

函数组件使用 useNavigate

在 React Router v6 及以上版本中,推荐使用 useNavigate Hook 来获取 navigate 函数。

import React from 'react';
import { useNavigate } from 'react-router-dom';const MyFunctionComponent = () => {const navigate = useNavigate();const handleNavigation = () => {navigate('/home'); // 使用 navigate 导航};return <button onClick={handleNavigation}>Go to Home</button>;
};export default MyFunctionComponent;

8、子组件的路由 Outlet

// App.js
import React from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import UserProfile from './UserProfile';
import UserSettings from './UserSettings';
import UserActivity from './UserActivity';const App = () => {return (<Router><Routes><Route path="/users/*" element={<UserProfile />}><Route path="settings" element={<UserSettings />} /><Route path="activity" element={<UserActivity />} /></Route></Routes></Router>);
};export default App;// UserProfile.js
import React from 'react';
import { Link, Outlet } from 'react-router-dom';const UserProfile = () => {return (<div><h1>User Profile</h1><nav><ul><li><Link to="settings">Settings</Link></li><li><Link to="activity">Activity</Link></li></ul></nav><Outlet /> {/* 渲染匹配的子路由 */}		// 路由</div>);
};export default UserProfile;// UserSettings.js
import React from 'react';const UserSettings = () => {return <h2>User Settings</h2>;
};export default UserSettings;// UserActivity.js
import React from 'react';const UserActivity = () => {return <h2>User Activity</h2>;
};export default UserActivity;

7、redux 集中状态管理

Redux.createStore 是 Redux 的传统方式,用于创建 Redux store。

Redux.createStore

  1. 导入 Redux:
import { createStore } from 'redux';
  1. 定义初始状态:
const initialState = {todos: [],
};
  1. 创建 Reducer:

Reducer 是一个纯函数,接受当前状态和 action,并返回新的状态。

const todoReducer = (state = initialState, action) => {switch (action.type) {case 'ADD_TODO':return { ...state, todos: [...state.todos, action.payload] };default:return state;}
};
  1. 创建 Store:

使用 createStore 创建 store,并传入 reducer。

const store = createStore(todoReducer);
  1. 使用 Store:

可以使用 store.getState() 获取当前状态,使用 store.dispatch(action) 发送 action。

store.dispatch({ type: 'ADD_TODO', payload: { text: 'Learn Redux' } });
console.log(store.getState());

Redux Toolkit

Redux Toolkit 是官方推荐的 Redux 工具集,它简化了 Redux 的使用,包含了一些开箱即用的工具和最佳实践。使用 Redux Toolkit 可以更容易地管理状态,减少模板代码。

1. 安装

首先,安装 Redux Toolkit 和 React-Redux:

npm install @reduxjs/toolkit react-redux
2. 创建 Slice

使用 createSlice 来定义 state、reducers 和 actions。这样可以简化代码结构。

import { createSlice } from '@reduxjs/toolkit';const todosSlice = createSlice({name: 'todos',initialState: [], // 要存的state// 使用 createSlice 创建 slice 时,定义的 reducer 函数会自动生成对应的 action creators。reducers: {addTodo: (state, action) => {	// state中包含所有 initialState 中的数据, state.push(action.payload); // 使用 Immer 库来处理不可变状态},removeTodo: (state, action) => {return state.filter(todo => todo.id !== action.payload);	// payload 包含了调用时传递的参数, 可以是对象},},
});// 导出 action
export const { addTodo, removeTodo } = todosSlice.actions;// 导出 reducer
export default todosSlice.reducer;
3. 配置 Store

使用 configureStore 来创建 store,它会自动添加 Redux DevTools 支持和中间件。

import { configureStore } from '@reduxjs/toolkit';
import todosReducer from './todosSlice';const store = configureStore({reducer: {todos: todosReducer,},
});export default store;
4. 连接 React 和 Redux

在应用中使用 Provider 将 store 传递给组件树。

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store';
import App from './App';ReactDOM.render(<Provider store={store}><App /></Provider>,document.getElementById('root')
);
5. 使用 Redux State

在组件中使用 useSelectoruseDispatch 来访问状态和发起 action。

import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { addTodo, removeTodo } from './todosSlice';const TodoList = () => {const todos = useSelector(state => state.todos);const dispatch = useDispatch();const handleAddTodo = () => {const text = prompt('Enter todo:');const id = Date.now(); // 简单生成 IDdispatch(addTodo({ id, text }));};const handleRemoveTodo = (id) => {dispatch(removeTodo(id));};return (<div><h1>Todo List</h1><ul>{todos.map(todo => (<li key={todo.id}>{todo.text}<button onClick={() => handleRemoveTodo(todo.id)}>Remove</button></li>))}</ul><button onClick={handleAddTodo}>Add Todo</button></div>);
};export default TodoList;
6. 处理异步操作

使用 createAsyncThunk 处理异步请求。

import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';// 异步操作示例
export const fetchTodos = createAsyncThunk('todos/fetchTodos', async () => {const response = await fetch('/api/todos');return response.json();
});const todosSlice = createSlice({name: 'todos',initialState: { items: [], status: 'idle' },reducers: {},extraReducers: (builder) => {builder.addCase(fetchTodos.fulfilled, (state, action) => {state.items = action.payload;});},
});// 导出 reducer
export default todosSlice.reducer;

8、hook

好的,我们来详细讲解一下 React Hooks,包括基本用法、常见的 Hooks 和具体的应用场景。

1、基本用法

React Hooks 是 React 16.8 引入的一种新特性,旨在让函数组件具备类组件的功能,尤其是状态管理和副作用处理。Hooks 的引入使得函数组件更加强大和灵活。

1. 使用 Hooks 的规则
  • 只能在函数组件或自定义 Hooks 中调用。 不可以在 普通 JavaScript 函数类组件 或者 条件语句 中调用。
  • 调用顺序必须一致。 React 会根据调用的顺序来追踪每个 Hook 的状态。

2、常见的 Hooks

1. useState

用于在函数组件中添加状态。

import React, { useState } from 'react';function Counter() {const [count, setCount] = useState(0); // count 是状态,setCount 是更新状态的函数return (<div><p>Count: {count}</p><button onClick={() => setCount(count + 1)}>Increment</button></div>);
}
2. useEffect

useEffect(()=> {}, 依赖项)
在这里插入图片描述

用于处理副作用,例如数据获取、订阅等。

import React, { useState, useEffect } from 'react';function DataFetcher() {const [data, setData] = useState(null);useEffect(() => {fetch('https://api.example.com/data').then(response => response.json()).then(data => setData(data));// 可选的清理函数return () => {// 例如取消订阅};}, []); // 依赖数组,空数组意味着仅在组件挂载时执行一次return <div>{data ? JSON.stringify(data) : 'Loading...'}</div>;
}
3. useContext

用于在组件之间共享状态,避免逐层传递 props。

import React, { createContext, useContext } from 'react';const ThemeContext = createContext('light');function ThemedComponent() {const theme = useContext(ThemeContext);return <div className={theme}>Current theme: {theme}</div>;
}function App() {return (<ThemeContext.Provider value="dark"><ThemedComponent /></ThemeContext.Provider>);
}
4. useReducer

用于在复杂状态逻辑中管理状态,相比 useState 更加灵活。

import React, { useReducer } from 'react';const initialState = { count: 0 };function reducer(state, action) {switch (action.type) {case 'increment':return { count: state.count + 1 };case 'decrement':return { count: state.count - 1 };default:throw new Error();}
}function Counter() {const [state, dispatch] = useReducer(reducer, initialState);return (<div>Count: {state.count}<button onClick={() => dispatch({ type: 'increment' })}>+</button><button onClick={() => dispatch({ type: 'decrement' })}>-</button></div>);
}
5. 自定义 Hooks

你可以创建自己的 Hooks,复用逻辑。

import { useState, useEffect } from 'react';function useFetch(url) {const [data, setData] = useState(null);const [error, setError] = useState(null);useEffect(() => {fetch(url).then(response => response.json()).then(setData).catch(setError);}, [url]);return { data, error };
}// 使用自定义 Hook
function DataFetcher({ url }) {const { data, error } = useFetch(url);if (error) return <div>Error: {error.message}</div>;return <div>{data ? JSON.stringify(data) : 'Loading...'}</div>;
}

3、具体的应用场景

  1. 数据获取: 使用 useEffectuseState 来从 API 获取数据。
  2. 表单管理: 使用 useState 来管理输入框的状态,并处理提交。
  3. 动画: 使用 useEffect 来设置动画的入场和离场。
  4. 订阅: 在 useEffect 中添加订阅,返回一个清理函数以取消订阅。
  5. 组合逻辑: 使用自定义 Hooks 来提取组件之间共享的逻辑。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/55736.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HCIP——GRE和MGRE

目录 VPN GRE GRE环境的搭建 GRE的报文结构 GRE封装和解封装报文的过程 GRE配置​编辑 R1 R2 GRE实验​​​​​​​​编辑 MGRE 原理 MGRE的配置 R1 R2 R3 R4 查看映射表 抓包 MGRE环境下的RIP网络 综合练习​编辑 VPN 说到GRE&#xff0c;我们先来说个大…

Http 协议和 RPC 协议有什么区别?

Http 协议和 RPC 协议有什么区别&#xff1f; 三个层面来述说&#xff1a; 从功能特性来说&#xff1a; HTTP是一个属于应用层的超文本传输协议&#xff0c;是万维网数据通信的基础&#xff0c;主要服务在网页端和服务端的数据传输上。 RPC是一个远程过程调用协议&#xff0…

AI+视频监控:EasyCVR安防平台赋能火电制造行业的视频智能管理方案

随着信息技术的飞速发展和智能制造的深入推进&#xff0c;火电制造行业作为国民经济的重要组成部分&#xff0c;正面临着智能化转型的迫切需求。为了提升生产效率、保障设备安全、优化管理流程&#xff0c;火电制造企业迫切需要引入先进的视频监控与人工智能技术。EasyCVR安防监…

TinyOS 点对基站通信

文章目录 一、前言1.1 发包的BlinkToRadio的数据包格式 二、混淆基站源码分析2.1 Makefile2.2 组件连接2.3 主逻辑代码 一、前言 1.1 发包的BlinkToRadio的数据包格式 如下&#xff0c;注意&#xff1a;AM层类型(1byte)即handlerID使可以在组件中修改的。 二、混淆基站源码…

《安富莱嵌入式周报》第343期:雷电USB4开源示波器正式发布,卓越的模拟前端低噪便携示波器,自带100W电源的便携智能烙铁,NASA航空航天锂电池设计

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 更新一期视频教程 【授人以渔】CMSIS-RTOS V2封装层专题视频&#xff0c;一期视频将常用配置和用法梳理清楚&#xff0…

【Mybatis篇】Mybatis的注解开发

&#x1f9f8;安清h&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;【计算机网络】&#xff0c;【Mybatis篇】 &#x1f6a6;作者简介&#xff1a;一个有趣爱睡觉的intp&#xff0c;期待和更多人分享自己所学知识的真诚大学生。 文章目录 &#x1f3af; Select注解 …

自动猫砂盆有必要买吗?高性价比的自动猫砂盆怎么选通通看这篇

最近市面上又新出了很多款式的自动猫砂盆&#xff0c;有些铲屎官蠢蠢欲动&#xff0c;但又在犹豫&#xff0c;自己真的需要自动猫砂盆吗&#xff1f;作为养猫4年的资深铲屎官&#xff0c;在买过这么多猫咪智能用品的里面&#xff0c;最不后悔的就是自动猫砂盆了&#xff01;要知…

【北京迅为】《STM32MP157开发板嵌入式开发指南》-第二十五章 Source Insight 的安装和使用

iTOP-STM32MP157开发板采用ST推出的双核cortex-A7单核cortex-M4异构处理器&#xff0c;既可用Linux、又可以用于STM32单片机开发。开发板采用核心板底板结构&#xff0c;主频650M、1G内存、8G存储&#xff0c;核心板采用工业级板对板连接器&#xff0c;高可靠&#xff0c;牢固耐…

ElasticSearch备考 -- Multi match

一、题目 索引task有3个字段a、b、c&#xff0c;写一个查询去匹配这三个字段为mom&#xff0c;其中b的字段评分比a、c字段大一倍&#xff0c;将他们的分数相加作为最后的总分数 二、思考 通过题目要求对多个字段进行匹配查询&#xff0c;可以考虑multi match、bool query操作。…

RabbitMQ的相关题

一、 MQ的作⽤及应⽤场景 类似问题: 项⽬什么场景下使⽤到了MQ, 为什么需要MQ? RabbitMQ 的作⽤?使⽤场景有哪些? RabbitMQ…

【JWT安全】portswigger JWT labs 全解

目录 1.利用有缺陷的 JWT 签名验证 ①接受任意签名 lab1:通过未验证的签名绕过 JWT 身份验证 ②接受无签名的token lab2:通过有缺陷的签名验证来绕过 JWT 身份验证 2.暴力破解密钥 ①使用hashcat lab3:通过弱签名密钥绕过 JWT 身份验证 3.JWT 标头参数注入 ①通过 jwk…

多模态大语言模型(MLLM)-InstructBlip深度解读

前言 InstructBlip可以理解为Blip2的升级版&#xff0c;重点加强了图文对话的能力。 模型结构和Blip2没差别&#xff0c;主要在数据集收集、数据集配比、指令微调等方面下文章。 创新点 数据集收集&#xff1a; 将26个公开数据集转换为指令微调格式&#xff0c;并将它们归类…

大数据新视界 --大数据大厂之 GraphQL 在大数据查询中的创新应用:优化数据获取效率

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

【C++】--类和对象(3)

&#x1f911;个人主页: 起名字真南 &#x1f911;个人专栏:【数据结构初阶】 【C语言】 【C】 目录 1 深入构造函数2 类型转换3 static成员4 友元函数5 内部类6 匿名对象 1 深入构造函数 之前我们实现构造函数的时候&#xff0c;初始化成员变量都是在函数体内赋值&#xff0c…

selenium有多个frame页时的操作方法(5)

之前文章我们提到&#xff0c;在webdriver.WebDriver类有一个switch_to方法&#xff0c;通过switch_to.frame()可以切换到不同的frame页然后才再定位某个元素做一些输入/点击等操作。 比如下面这个测试网站有2个frame页&#xff1a;http://www.sahitest.com/demo/framesTest.h…

5.toString()、构造方法、垃圾回收、静态变量与静态方法、单例设计模式、内部类

文章目录 一、toString()1. 优缺点2. 使用方法举例① Dos类里更省事的方法 ② Application里 二、构造方法1. 导入2. 什么是构造方法3. 怎么写构造方法① 无参的构造方法(无参构造器)② 有参的构造方法(有参构造器)③ 注意 4. 构造方法的重载 三、再探this1. 给成员变量用2. 给…

【用户管理 添加用户 超级用户 用户和组】

用户管理 添加用户超级用户用户和组 添加用户 介绍用户的管理操作 比如&#xff0c;添加一个用户 sudo useradd -m test1 其中&#xff0c;sudo表示管理员身份运行 修改用户密码 sudo passwd test1 删除用户 sudo userdel test 超级用户 1.首次使用时&#xff0c;需要给roo…

快速区分 GPT-3.5 与 GPT-4

问&#xff1a;鲁迅为什么暴打周树人&#xff1f; GPT3.5回答 各种稀奇古怪的理由 GPT4回答 正确区分鲁迅和周树人是同一个人 国内GPT入口 https://ai-to.cn/url/?ulihaimao

Android Preference的使用以及解析

简单使用 values.arrays.xml <?xml version"1.0" encoding"utf-8"?> <resources><string-array name"list_entries"><item>Option 1</item><item>Option 2</item><item>Option 3</item&…

初始Linux(二)基础命令

前言&#xff1a; 之前那一篇我们已经介绍了一部分的基础命令&#xff0c;当然那只不过是九牛一毛&#xff0c;本篇我们继续介绍一些比较重要且需要掌握的基础命令。 mv命令&#xff1a; 其实这个命令有两个功能&#xff0c;一个是移动&#xff08;剪切&#xff09;文件&#…