当前位置: 首页 > news >正文

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 来提取组件之间共享的逻辑。

相关文章:

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

React 是一个用于构建用户界面的 JavaScript 库&#xff0c;由 Facebook 开发并维护。它的核心理念是“组件化”&#xff0c;即将用户界面拆分为可重用的组件。 React 的组件通常使用 JSX&#xff08;JavaScript XML&#xff09;。JSX 是一种 JavaScript 语法扩展&#xff0c;…...

如何加密重要U盘?U盘怎么加密保护?

在日常生活中&#xff0c;我们常常使用U盘来存储和传输重要文件。然而&#xff0c;U盘的便携性也意味着它容易丢失或被盗。为了保护U盘中的数据安全&#xff0c;我们需要对U盘进行加密。本文将为您介绍如何加密重要U盘&#xff0c;以及U盘加密保护的方法。 BitLocker BitLocke…...

js编写一个中奖程序

好的&#xff0c;以下是一个用JavaScript编写的抽奖程序&#xff0c;它根据给定的概率来决定奖项。我们将使用随机数生成器来模拟抽奖过程。 function drawPrize() {const prizes [{ name: 特等奖, probability: 0.00000001 },{ name: 一等奖, probability: 0.00000003 },{ n…...

Mybatis-plus的基础用法

文章目录 1. 核心功能1.1 配置与编写规则1.2 条件构造器1.3 自定义SQL1.4 IService接口1.4.1 Lambda方法1.4.2 批量新增 1.5 分页查询 2. 拓展功能2.1 代码生成器2.2 DB静态工具2.3 逻辑删除2.4 枚举处理器 参考 1. 核心功能 1.1 配置与编写规则 Maven依赖&#xff1a; <…...

【网络篇】计算机网络——应用层详述(笔记)

目录 一、应用层协议原理 1. 进入应用层 2. 网络应用程序体系结构 &#xff08;1&#xff09;客户-服务器体系结构&#xff08;client-server architecture&#xff09; &#xff08;2&#xff09; P2P 体系结构&#xff08;P2P architecture&#xff09; 3. 进程间通讯 …...

力扣10.9

3171. 找到按位或最接近 K 的子数组 给你一个数组 nums 和一个整数 k 。你需要找到 nums 的一个 子数组 &#xff0c;满足子数组中所有元素按位或运算 OR 的值与 k 的 绝对差 尽可能 小 。换言之&#xff0c;你需要选择一个子数组 nums[l..r] 满足 |k - (nums[l] OR nums[l 1…...

@RequestMapping指定请求方式的用法

RequestMapping("/depts")public Result list() {log.info("查询全部部分数据");return Result.success();}上面代码没有指定请求方式&#xff0c;通过postman测试&#xff0c;可以用GET&#xff0c;POST&#xff0c;Delete的方式调用。 要想指定请求方式…...

卷积神经网络细节问题及知识点

一、Batch Normalization Batch Normalization&#xff08;BN&#xff0c;批归一化&#xff09; 是深度学习中的一种技术&#xff0c;主要用于加速神经网络的训练过程&#xff0c;同时提高网络的稳定性和收敛速度。它通过对每一层的输出进行归一化&#xff0c;减少梯度消失和梯…...

【图论】(一)图论理论基础与岛屿问题

图论理论基础与岛屿问题 图论理论基础深度搜索&#xff08;dfs&#xff09;广度搜索&#xff08;bfs&#xff09;岛屿问题概述 岛屿数量岛屿数量-深搜版岛屿数量-广搜版 岛屿的最大面积孤岛的总面积沉没孤岛建造最大人工岛水流问题岛屿的周长 图论理论基础 这里仅对图论相关核…...

PhotoMaker部署文档

一、介绍 PhotoMaker&#xff1a;一种高效的、个性化的文本转图像生成方法&#xff0c;能通过堆叠 ID 嵌入自定义逼真的人类照片。相当于把一张人的照片特征提取出来&#xff0c;然后可以生成你想要的不同风格照片&#xff0c;如写真等等。 主要特点&#xff1a; 在几秒钟内…...

双十一买什么最划算?2024年双十一选购攻略汇总!

随着一年一度的双十一购物狂欢节日益临近&#xff0c;消费者们纷纷摩拳擦掌&#xff0c;准备在这个全球最大的购物盛宴中抢购心仪已久的商品。双十一不仅是一场购物的狂欢&#xff0c;更是商家们推出优惠、促销的绝佳时机。然而&#xff0c;面对琳琅满目的商品和纷繁复杂的优惠…...

Oracle架构之物理存储之审计文件

文章目录 1 审计文件&#xff08;audit files&#xff09;1.1 定义1.2 查看审计信息1.3 审计相关参数1.4 审计的类型1.4.1 语句审计1.4.2 权限审计1.4.3 对象审计1.4.4 细粒度的审计 1.5 与审计相关的数据字典视图 1 审计文件&#xff08;audit files&#xff09; 1.1 定义 审…...

DAY6 面向对象

概念 对象是一种特殊的数据结构&#xff0c;可以用来记住一个事物的数据&#xff0c;从而代表该事物&#xff0c;可以理解为一个模板表&#xff0c;总而言之万物皆对象&#xff0c;比如一个人、一个物体等。 怎么创建对象 先设计对象的模板&#xff0c;也就是对象的设计图&a…...

代码随想录 (三)—— 哈希表部分刷题

当我们想使用哈希法来解决问题的时候&#xff0c;我们一般会选择如下三种数据结构。 数组set &#xff08;集合&#xff09;map(映射) 在java中有就是&#xff0c;hashmap, LinkedHashMap, TreeMap &#xff0c;HashTable 等 总结一下&#xff0c;当我们遇到了要快速判断一个…...

搜维尔科技:使用 SenseGlove Nova 2 远程操作机械手,实现了对鸡蛋的精细操控

使用SenseGlove Nova 2远程操作机械手&#xff0c;实现了对鸡蛋的精细操控 搜维尔科技&#xff1a;使用 SenseGlove Nova 2远程操作机械手&#xff0c;实现了对鸡蛋的精细操控...

Mybatis是什么?优缺点分别有哪些?

MyBatis 是一个开源的持久层框架&#xff0c;它提供了将 SQL 语句和 Java 对象进行映射的功能&#xff0c;使得开发者可以通过简单的配置来实现数据库操作&#xff0c;减少了手写 SQL 的工作量。 MyBatis 的优点&#xff1a; 1. 简单易用&#xff1a;MyBatis 采用了简单的配置…...

opencascade鼠标拖拽框选功能

1.首先在OccView中添加用于显示矩形框的类 //! rubber rectangle for the mouse selection.Handle(AIS_RubberBand) mRectBand; 2.设置框选的属性 mRectBand new AIS_RubberBand(); //设置属性 mRectBand->SetLineType(Aspect_TOL_SOLID); //设置变宽线型为实线 mRe…...

docker 部署 postgres

这里以postgres:12.6为例&#xff1a; 1. 拉取postgres镜像 docker pull postgres:12.62. 创建挂载目录 mkdir -p /mydata/docker/postgres-1/data3. 启动postgres容器 docker run --name postgres-12.6 \-e POSTGRES_PASSWORD123456 \-p 5432:5432 \-v /mydata/docker/pos…...

【重学 MySQL】五十、添加数据

【重学 MySQL】五十、添加数据 使用INSERT INTO语句添加数据基本语法示例插入多行数据注意事项 使用LOAD DATA INFILE语句批量添加数据其他插入数据的方式注意事项 在MySQL中&#xff0c;添加数据是数据库操作中的基本操作之一。 使用INSERT INTO语句添加数据 使用 INSERT IN…...

硬货!Zabbix监控AIX系统服务案例

本文将介绍如何使用Zabbix自定义键值脚本方式监控AIX 系统IBM CICS中间件进程服务以及日志文件等信息。 Customer Information Control System (CICS) Transaction Server 是 IBM 针对 z/OS 的多用途事务处理软件。这是一个功能强大的应用程序服务器&#xff0c;用于大型和小型…...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型&#xff08;LLM&#xff09;参数规模的增长&#xff0c;推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长&#xff0c;而KV缓存的内存消耗可能高达数十GB&#xff08;例如Llama2-7B处理100K token时需50GB内存&a…...

C++.OpenGL (20/64)混合(Blending)

混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...

Redis:现代应用开发的高效内存数据存储利器

一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发&#xff0c;其初衷是为了满足他自己的一个项目需求&#xff0c;即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源&#xff0c;Redis凭借其简单易用、…...

[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.

ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #&#xff1a…...

【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error

在前端开发中&#xff0c;JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作&#xff08;如 Promise、async/await 等&#xff09;&#xff0c;开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝&#xff08;r…...

从物理机到云原生:全面解析计算虚拟化技术的演进与应用

前言&#xff1a;我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM&#xff08;Java Virtual Machine&#xff09;让"一次编写&#xff0c;到处运行"成为可能。这个软件层面的虚拟化让我着迷&#xff0c;但直到后来接触VMware和Doc…...