听过哪些与React相关的名词:
今天主要介绍:React 18.3
以下分享源码在此
1、虚拟 DOM(Virtual DOM):
React 使用虚拟 DOM 渲染流程。
<body>
<div id="root"></div>
<!-- 引入React.js -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<!-- 引入ReactDOM.js -->
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/babel-standalone/babel.min.js"></script>
<script type="text/babel">
function handleClick() {
alert('Div element clicked!');
}
//React.createElement是React官方提供创建虚拟dom的一个api.
const element = React.createElement(
'div',
{ className: 'redBg', onClick: handleClick },
'Item 1'
);
//JSX语法,经过Babel编译器,转化成React.createElement()
const element2 = (
<div className="redBg" onClick={handleClick}>
Item 1
</div>
);
//将虚拟 DOM(React 元素)渲染到真实 DOM 的过程: 1.获取页面元素-->2.创建容器-->3.将虚拟元素渲染到容器内
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(element);
const realDom = document.getElementById('realDom');
console.log('virtualDom', element);
console.log('realDom', realDom);
</script>
</body>
虚拟dom总结:
- 本质:JS对象,相对真实dom,相对真实dom是一个轻量级的对象。
- 优点:
1、最小化真实dom操作,减少重绘(Repaint)和重排(Reflow)次数。
重排:受DOM的布局、尺寸、位置等发生变化时影响
重绘:受DOM的外观(如颜色、边框、背景)发生变化时影响
2、快速开发,组件复用。
- 缺点:多一份虚拟dom内存开销。
2、JSX:
JSX是一种用于描述 UI 的JavaScript 语法扩展,允许在 JavaScript 中编写类似 HTML 的代码。
编译器Babel将jsx代码编译成React.createElement。
- 单行写法
const element = <h1>Hello, world!</h1>;
- 多行写法
const element2 = (
<div className="redBg" onClick={handleClick}>
muplti line
</div>
);
- 传参,可用插入表达式
const itemName = 'Item 2';
const element3 = (
<div className="redBg" onClick={handleClick}>
{itemName}
</div>
);
- 复杂点的写法,多写点JS方法
const items = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry'];
const element = (
<div className="fruit-list">
<h1>Fruit List</h1>
<ul>
{items.map((item, index) => (
<li key={index} className="fruit-item">
{item}
</li>
))}
</ul>
<footer>
<p>Total items: {items.length}</p>
</footer>
</div>
);
// 渲染到页面
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(element);
- 根元素
如何不增加额外 DOM 节点
错误写法:
const element = (
<h1>Hello</h1>
<p>This is a paragraph.</p>
);
纠正写法:
const element = (
<React.Fragment>
<h1>Hello</h1>
<p>This is a paragraph.</p>
</React.Fragment>
);
简易写法:
const element = (
<React.Fragment>
<h1>Hello</h1>
<p>This is a paragraph.</p>
</React.Fragment>
);
总结:
<> ... </> = <React.Fragment>... </React.Fragment>
而在angular中,刚好相反,是在HTML 的代码编写js代码
<div>
<p>{{ message }}</p>
<button (click)="updateMessage()">Click me</button>
</div>
3、组件(Component):
React 的核心概念,UI 的构建块。组件可以是函数组件或类组件
- 类组件
class ClassComponent extends Component {
constructor(props) {
super(props);
// 初始化 state
this.state = {
count: 0,
};
}
componentDidMount() {
// 组件挂载后调用
console.log('Component did mount');
}
shouldComponentUpdate(nextProps, nextState) {
// 控制组件是否需要重新渲染
return nextState.count !== this.state.count;
}
componentDidUpdate(prevProps, prevState) {
// 组件更新后调用
console.log('Component did update');
}
componentWillUnmount() {
// 组件卸载之前调用
console.log('Component will unmount');
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.handleClick}>Increment</button>
</div>
);
}
}
ClassComponent.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number,
onValueChange: PropTypes.func,
};
export default ClassComponent;
- 函数组件
import React from 'react'
import './Style.css';
function FCComponent() {
return (
<div className='bg-yellow center'>这是函数组件</div>
)
}
export default FCComponent
3、状态(State):
1.是组件内部的状态。
2.可变,通常在组件内部管理和更新。
3.用于管理组件自身的数据和状态。
- 类组件的state
constructor(props) {
super(props);
// 初始化 state
this.state = {
count: 0,
name: '',
age: 0
};
}
- 函数组件的state
const [count, setCount] = useState(0);
const [name, setName] = useState('');
const [age, setAge] = useState(0);
4、属性(Props):
1.是组件的属性,用于从父组件传递数据和回调函数。
2.不可变,子组件不能直接修改。
3.用于将数据和功能从父组件传递到子组件。
function Welcome(props) {
return <h1>Hello, {props.name}!</h1>;
}
5、生命周期方法(Lifecycle Methods):
类组件中特定的钩子函数,用于在组件的不同阶段执行代码,如 componentDidMount、componentDidUpdate 和 componentWillUnmount。
class ComponentA extends Component {
constructor(props) {
super(props);
this.state = {
// 初始化 state
};
}
static getDerivedStateFromProps(nextProps, prevState) {
// 用于根据新的 props 更新 state
return null;
}
componentDidMount() {
// 组件挂载后调用
}
shouldComponentUpdate(nextProps, nextState) {
// 控制组件是否需要重新渲染
return true;
}
static getSnapshotBeforeUpdate(prevProps, prevState) {
// 在更新之前获取快照
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
// 组件更新后调用
}
componentWillUnmount() {
// 组件卸载之前调用
}
render() {
return (
<div>
{/* 组件内容 */}
</div>
);
}
}
ComponentA .propTypes = {
// 定义 prop 类型
};
export default Second;
6、Hooks:
React 16.8 引入的特性,允许在函数组件中使用状态和其他 React 特性,如 useState 和 useEffect。
7、组件通讯:
pubsub使用:
安装
(1) npm install pubsub-js --save
导入
(2) import PubSub from "pubsub-js"
class Publisher extends React.Component {
constructor(props) {
super(props);
this.state = {
num: 0
};
}
componentDidMount() {
// 假设我们在组件挂载后发布一个事件
setInterval(() => {
PubSub.publish('someChannel', { message: 'Hello from Publisher!'+ this.state.num });
this.setState({
num: this.state.num + 1
});
}, 1000);
}
render() {
return <div>Publisher Component</div>;
}
}
class Subscriber extends React.Component {
componentDidMount() {
// 订阅事件
this.token = PubSub.subscribe('someChannel', (msg, data) => {
console.log(data.message, msg); // 输出: Hello from Publisher!
});
}
componentWillUnmount() {
// 组件卸载时取消订阅,防止内存泄漏
PubSub.unsubscribe(this.token);
}
render() {
return <div>Subscriber Component</div>;
}
}
8、上下文(Context):
用于在组件树中传递数据,而不需要通过每层组件手动传递 props
import React, { createContext, Component } from 'react';
// 创建一个 Context 对象
const MyContext = createContext();
// 创建一个提供 Context 的组件
class MyProvider extends Component {
state = {
user: {
name: 'Alice',
age: 30
}
};
setUser = (name, age) => {
this.setState({
user: { name, age }
});
};
render() {
return (
<MyContext.Provider value={{
user: this.state.user,
setUser: this.setUser
}}>
{this.props.children}
</MyContext.Provider>
);
}
}
import React, { Component } from 'react';
// 创建一个消费 Context 的组件
class ChildComponent extends Component {
static contextType = MyContext;
handleChangeUser = () => {
const { setUser } = this.context;
setUser('Bob', 25);
};
render() {
const { user } = this.context;
return (
<div>
<p>User Name: {user.name}</p>
<p>User Age: {user.age}</p>
<button onClick={this.handleChangeUser}>Change User</button>
</div>
);
}
}
// 创建一个消费 Context 的组件
class Child2Component extends Component {
static contextType = MyContext;
handleChangeUser = () => {
const { setUser } = this.context;
setUser('Bob--22', 250);
};
render() {
const { user } = this.context;
return (
<div>
<p>User Name: {user.name}</p>
<p>User Age: {user.age}</p>
<button onClick={this.handleChangeUser}>Change User</button>
</div>
);
}
}
// 创建一个顶层父组件
class ParentContextComponent extends Component {
render() {
return (
<MyProvider>
<div className='center'>
<h1>上下文Context Component</h1>
<ChildComponent />
<br/>
<Child2Component />
</div>
</MyProvider>
);
}
}
export default ParentContextComponent;
9、Redux:
一个流行的状态管理库,常与 React 一起使用,帮助管理应用的全局状态。
由于内容比较多,下次再专门做个分享会。
10、插槽:
先来看一段angular的代码
先定义一个包含插槽的组件container.component:
<div class="parent">
<h1>Parent Component</h1>
<!-- 第一个插槽 -->
<ng-content select="[header]"></ng-content>
<hr/>
<!-- 第二个插槽 -->
<ng-content select="[body]"></ng-content>
<hr/>
<!-- 第三个插槽 -->
<ng-content select="[footer]"></ng-content>
</div>
调用container.component,插入需要不同位置的代码
<!-- app.component.html -->
<app-parent>
<div header>
<h2>This is the Header Content</h2>
</div>
<div body>
<p>This is the Body Content</p>
</div>
<div footer>
<p>This is the Footer Content</p>
</div>
</app-parent>
下面再看一下React的代码
先定义一个包含插槽的组件container.component:
import React, { Component } from 'react';
class ParentComponent extends Component {
render() {
const { header, body, footer } = this.props;
return (
<div className="parent">
<h1>Parent Component</h1>
{/* 渲染不同的插槽内容 */}
<div className="header">{header}</div>
<hr/>
<div className="body">{body}</div>
<hr/>
<div className="footer">{footer}</div>
</div>
);
}
}
export default ParentComponent;
将内容作为 props 传递给 ParentComponent 的不同插槽
import React, { Component } from 'react';
import ParentComponent from './ParentComponent';
class App extends Component {
render() {
return (
<ParentComponent
header={<h2>This is the Header Content</h2>}
body={<p>This is the Body Content</p>}
footer={<p>This is the Footer Content</p>}
/>
);
}
}
export default App;
以上是本次分享,谢谢大家。