本文用来记录我的React学习过程,借鉴了很多大佬的文章,收获不少,如果有不对的地方,请大家指正😊!
组件通常需要根据交互更改屏幕上显示的内容。输入表单应该更新输入字段,单击轮播图上的“下一个”应该更改显示的图片,单击“购买”应该将商品放入购物车。组件需要“记住”某些东西:当前输入值、当前图片、购物车。在 React 中,这种组件特有的记忆被称为 state。
直接上代码:
import { useState } from 'react';
import { sculptureList } from './data.js';
export default function Gallery() {
const [index, setIndex] = useState(0);
function handleClick() {
setIndex(index + 1);
}
let sculpture = sculptureList[index];
return (
<>
<button onClick={handleClick}>
Next
</button>
<h2>
<i>{sculpture.name} </i>
by {sculpture.artist}
</h2>
<h3>
({index + 1} of {sculptureList.length})
</h3>
<img
src={sculpture.url}
alt={sculpture.alt}
/>
<p>
{sculpture.description}
</p>
</>
);
}
在 React 中,useState 以及任何其他以“use”开头的函数都被称为 Hook。
Hook 是特殊的函数,只在 React 渲染时有效。
React 组件使用 props 来互相通信。每个父组件都可以提供 props 给它的子组件,从而将一些信息传递给它。Props 可能会让你想起 HTML 属性,但你可以通过它们传递任何 JavaScript 值,包括对象、数组和函数。
这里主要展示一下父组件向子组件传值
父组件Profile
export default function Profile() {
return (
<Avatar
person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }}
size={100}
/>
);
}
子组件Avatar
function Avatar({ person, size }) {
return (
<img
className="avatar"
src={getImageUrl(person)}
alt={person.name}
width={size}
height={size}
/>
);
}
使用 ref 操作 DOM
获取指向节点的 ref
要访问由 React 管理的 DOM 节点,首先,引入 useRef Hook:
import { useRef } from 'react';
然后,在你的组件中使用它声明一个 ref:
const myRef = useRef(null);
最后,将 ref 作为 ref 属性值传递给想要获取的 DOM 节点的 JSX 标签:
<div ref={myRef}>
useRef Hook 返回一个对象,该对象有一个名为 current 的属性。最初,myRef.current 是 null。当 React 为这个
// 你可以使用任意浏览器 API,例如:
myRef.current.scrollIntoView();
这里的 ref 指向一个数字,但是,像 state 一样,你可以让它指向任何东西:字符串、对象,甚至是函数。与 state 不同的是,ref 是一个普通的 JavaScript 对象,具有可以被读取和修改的 current 属性。
请注意,组件不会在每次递增时重新渲染。 与 state 一样,React 会在每次重新渲染之间保留 ref。但是,设置 state 会重新渲染组件,更改 ref 不会!
stste和refs的比较
state | refs |
---|---|
useRef(initialValue)返回 { current: initialValue } | useState(initialValue) 返回 state 变量的当前值和一个 state 设置函数 ( [value, setValue]) |
更改时不会触发重新渲染 | 更改时触发重新渲染 |
可变 —— 你可以在渲染过程之外修改和更新 current 的值 | “不可变” —— 你必须使用 state 设置函数来修改 state 变量,从而排队重新渲染 |
你不应在渲染期间读取(或写入) current 值 | 你可以随时读取 state。但是,每次渲染都有自己不变的 state 快照 |
旧版
挂载阶段
constructor
componentWillMount
render
componentDidMount
更新阶段
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
卸载阶段
componentWillUnmount
新版
挂载阶段
constructor
getDerivedStateFromProps
render
componentDidMount
更新阶段
getDerivedStateFromProps
shouldComponentUpdate
render
getSnapshotBeforeUpdate
componentDidUpdate
卸载阶段
componentWillUnmount
构造函数,通常用于初始化组件的状态和绑定方法
constructor(props) {
super(props);
this.state = { count: 0 };
this.handleClick = this.handleClick.bind(this);
}
补充:
.bind()方法: Function.prototype.bind()方法创建一个新的函数,当这个新函数被调用时,它的this值会被设置为提供的值,并且其参数也会被预先设定。
用来返回组件的UI结构,它是一个纯函数,其中不应该包含任何副作用或改变状态的操作。
import React,{Component} from 'react'
export default class Hello extends Component{
render(){
return <h2>Hello,React!</h2>
}
}
这个函数是在组件挂载到DOM后执行的,可以在这里获取数据、进行一些异步请求或DOM操作。
componentDidMount() {
// 发起API请求或其他初始化操作
fetchData().then(data => {
this.setState({ data
});
});
}
这个函数是用来判断组件是否需要重新渲染,返回一个布尔值,可以优化性能。
shouldComponentUpdate(nextProps, nextState) {
// 这里假设props有一个min属性,表示计数器的最小值
if (nextProps.min !== undefined && nextState.count < nextProps.min) {
return false;
}
return true;
}
注意:此钩子函数有个setState(),在组件中,每当调用this.setState()方法时,就会触发shouldComponentUpdate(),如果函数返回true就更新状态,否则不更新。
强制更新
当调用forceUpdate()时,会直接来到componentWillUpdate()钩子函数。
何时使用: 只想更新一下组件,但是不想对状态作出任何的更改,就可以调用,通过this.forceUpdate()直接调用
componentDidUpdate(prevProps, prevState):组件更新后触发,用于处理更新后的操作。
componentDidUpdate(prevProps, prevState) {
console.log('组件已更新完毕');
if (prevProps.id !== this.props.id) {
// 处理props变化的逻辑
console.log('props.id变了');
}
}
componentWillUnmount():这个函数是在组件卸载前执行的,可以在这里进行一些清理工作,比如取消订阅、清除定时器、取消异步请求或移除事件监听器等。
componentDidUpdate()
componentDidUpdate(prevProps,prevState,snapshot):它在组件更新(即render() 方法执行后)后被调用。它接收三个参数:prevProps、prevState、snapshot。与旧的钩子函数相比,多了一个参数snapshot。
componentDidUpdate(prevProps, prevState, snapshot) {
if (this.props.data !== prevProps.data) {
console.log('this.props中的数据变了');
}
// 使用getSnapshotBeforeUpdate()的返回值
if (snapshot !== null) {
console.log('Snapshot from getSnapshotBeforeUpdate:', snapshot);
}
}
注意:如果getSnapshotBeforeUpdate()有返回值,它会成为componentDidUpdate()的第三个参数,你可以在这里使用它。
getDerivedStateFromProps(nextProps,prevState):是一个静态方法,用于在组件接收新的props时计算并返回新的state。这个方法在React 16.3版本之后引入,用来替代不推荐使用的componentWillReceiveProps()方法。
class MyComponent extends React.Component {
static getDerivedStateFromProps(nextProps, prevState) {
// 根据 nextProps 和 prevState 计算并返回新的 state
if (nextProps.value !== prevState.value) {
return { value: nextProps.value };
}
return null; // 如果不需要更新 state,返回 null
}
constructor(props) {
super(props);
this.state = {
value: props.value,
};
}
render() {
return <div>{this.state.value}</div>;
}
}
以下是getDerivedStateFromProps() 的主要特点和使用方式:
静态方法:getDerivedStateFromProps() 是一个静态方法,因此不能访问实例的this,它只接收两个参数:nextProps 和 prevState。
计算新的state:通常,你可以在这个方法内部根据nextProps 和 prevState 来计算并返回新的state。这个新的state将在组件更新时应用。
不触发副作用:与componentDidUpdate() 不同,getDerivedStateFromProps() 不应执行副作用,如发起网络请求。它只用于计算state。
适用于控制组件内部状态:getDerivedStateFromProps() 主要用于控制组件内部的状态,以确保它与外部传入的props保持同步。
getSnapshotBeforeUpdate(nextProps,prevState):它在组件更新(即将应用新props或state并重新渲染)之前触发。它允许你捕获组件更新前的一些信息,并在组件更新后使用这些信息。
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
getSnapshotBeforeUpdate(prevProps, prevState) {
// 捕获组件更新前的滚动位置
if (prevProps.items.length < this.props.items.length) {
const scrollHeight = this.myRef.current.scrollHeight;
const scrollTop = this.myRef.current.scrollTop;
return { scrollHeight, scrollTop };
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
// 使用snapshot来恢复滚动位置
if (snapshot !== null) {
this.myRef.current.scrollTop = snapshot.scrollTop + (this.myRef.current.scrollHeight - snapshot.scrollHeight);
}
}
render() {
// 使用ref来获取DOM元素的引用
return <div ref={this.myRef}>{/* 组件内容 */}</div>;
}
}
在本示例中,getSnapshotBeforeUpdate() 用于捕获滚动位置,然后在componentDidUpdate() 中使用snapshot来恢复滚动位置,以确保用户在滚动列表时不会在更新后失去滚动位置。
以下是关于getSnapshotBeforeUpdate() 的主要特点和用法:
触发时机:getSnapshotBeforeUpdate() 在render() 方法被调用后、组件DOM更新前触发,通常用于在更新前捕获一些DOM信息。
接收两个参数:这个生命周期方法接收两个参数:prevProps、prevState。你可以使用这些参数来比较前后的props和state。
返回值:getSnapshotBeforeUpdate()
方法应该返回一个值(通常是一个对象),它将成为componentDidUpdate()
方法的第三个参数。这个返回值通常用于保存一些DOM相关的信息,比如滚动位置。
通常和componentDidUpdate()一起使用:getSnapshotBeforeUpdate()
结合componentDidUpdate(prevProps, prevState, snapshot)
使用,snapshot参数是getSnapshotBeforeUpdate() 的返回值。你可以在componentDidUpdate()
中使用snapshot来执行DOM操作或其他一些操作。