Заметки об изучении системы React — супер базовые — супер подробные — супер лаконичные — компонентно-ориентированное программирование React (2)

Часть 2: компонентно-ориентированное программирование React

1 Основное понимание и использование

Отладка с помощью React DevTools

React Developer Tools

важная точка

  • Имена компонентов должны быть написаны с заглавной буквы

  • Виртуальный элемент DOM может иметь только один корневой элемент.

  • Виртуальные элементы DOM должны иметь закрывающие теги < />

Базовый процесс рендеринга тегов компонента класса

  • React внутренне создает объекты экземпляра компонента

  • Вызовите render(), чтобы получить виртуальный DOM и преобразовать его в настоящий DOM.

  • Вставить внутрь указанного элемента страницы

1.1 Определение компонентов в React

Функционально объявить компоненты

<script type="text/babel">
	//1.创建函数式组件
	function MyComponent(){
    
    
		console.log(this); //此处的this是undefined,因为babel编译后开启了严格模式
		return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>
	}
	//2.渲染组件到页面
	ReactDOM.render(<MyComponent/>,document.getElementById('test'))
</script>

После выполнения ReactDOM.render(<MyComponent/>..., что произошло

  • React анализирует тег компонента и находит компонент MyComponent.

  • Обнаружено, что компонент определяется с помощью функции, а затем вызывается функция для преобразования возвращенного виртуального DOM в реальный DOM, который затем отображается на странице.

Компоненты класса (следующие примеры относятся к компонентам класса)

<script type="text/babel">
	//1.创建类式组件
	//必须继承Component类,必须要写render,必须有返回值
	class MyComponent extends React.Component {
    
    
		render(){
    
    
			//render是放在哪里的?—— MyComponent的原型对象上,供实例使用。
			//render中的this是谁?—— MyComponent的实例对象 <=> MyComponent组件实例对象。
			console.log('render中的this:',this);
			return <h2>我是用类定义的组件(适用于【复杂组件】的定义)</h2>
		}
	}
	//2.渲染组件到页面
	ReactDOM.render(<MyComponent/>,document.getElementById('test'))
</script>

После выполнения ReactDOM.render(<MyComponent/>..., что произошло

  • React анализирует тег компонента и находит компонент MyComponent.

  • Обнаружено, что компонент определяется с помощью класса, а затем заново создается экземпляр класса, и метод рендеринга на прототипе вызывается через экземпляр.

  • Преобразуйте виртуальный DOM, возвращенный рендерингом, в реальный DOM, а затем отобразите его на странице.

Простые и сложные компоненты

Компоненты с состоянием — это сложные компоненты, компоненты без состояния — это простые компоненты.

Страница, управляемая состоянием: данные помещаются в состояние компонента, и изменение данных будет управлять отображением страницы.

Состояние состояния находится в экземпляре компонента

2 Один из трех основных атрибутов экземпляров компонентов: состояние

2.1 Понимание состояния

  • состояние является наиболее важным атрибутом объекта компонента, а значение является объектом (может содержать несколько комбинаций ключ:значение)

  • Компонент вызывается 状态机, и соответствующее отображение страницы обновляется путем обновления состояния компонента (повторного рендеринга компонента)

  • Данные помещаются в состояние, а состояние управляет отображением страницы! Отображение страницы, управляемое состоянием! Отображение страницы, управляемое состоянием!

2.2 На что следует обратить внимание

this в методе рендеринга в компоненте является объектом экземпляра компонента

В пользовательском методе компонента это не определено (используется как обратный вызов), как это решить?

  • Обязательная привязка этого: через bind() объекта функции

  • this.changeWeather = this.changeWeather.bind(this)Таким образом, после написания вызывается метод на самом экземпляре объекта вместо того, чтобы висеть на прототипе

  • оператор присваивания + стрелочная функция推荐

Данные о состоянии, которые нельзя изменить или обновить напрямую, необходимо setStateобновлять с помощью

Методы в классе в основном используются как обратные вызовы событий, так что разберитесь с этим.

Если вы хотите использовать его, вам нужно написать много методов в конструкторе this.changeWeather = this.changeWeather.bind(this), что слишком громоздко (упростите конструктор, сохраните или вызовите это----упрощенное написание)

2.3 Пример кода

Обычно используйте bind() объекта функции

<script type="text/babel">
	//1.创建组件
	class Weather extends React.Component {
    
    

		//构造器调用几次? ———— 1次
		constructor(props) {
    
    
			console.log('constructor');
			super(props)
			//初始化状态
			this.state = {
    
     isHot: false, wind: '微风' }
			//解决changeWeather中this指向问题---原型上得有,然后生成这个实例身上自身的方法
			this.changeWeather = this.changeWeather.bind(this)
		}

		//render调用几次? ———— 1+n次 1是初始化的那次 n是状态更新的次数
		render() {
    
    
			console.log('render');
			//读取状态
			const {
    
     isHot, wind } = this.state
			//绑定事件不用写括号,不然就是把返回值交给onClick,我们是要把整个回调函数交给onClick
			//这边现在调用的changeWeather方法是实例自身上的
			return <h1 onClick={
    
    this.changeWeather}>今天天气很{
    
    isHot ? '炎热' : '凉爽'}{
    
    wind}</h1>
		}

		//changeWeather调用几次? ———— 点几次调几次
		changeWeather() {
    
    
			//changeWeather放在哪里? ———— Weather的原型对象上,供实例使用
			//由于changeWeather是作为onClick的回调,所以不是通过实例调用的,是直接调用this应该是window
			//但类中的方法默认开启了局部的严格模式,所以changeWeather中的this为undefined

			console.log('changeWeather');
			//获取原来的isHot值
			const isHot = this.state.isHot
			//严重注意:状态必须通过setState进行更新,且更新是一种合并,不是替换。
			this.setState({
    
     isHot: !isHot })
			console.log(this);

			//严重注意:状态(state)不可直接更改,下面这行就是直接更改!!!
			//this.state.isHot = !isHot //这是错误的写法
		}
	}
	//2.渲染组件到页面
	ReactDOM.render(<Weather />, document.getElementById('test'))
</script>

Сокращенный метод: форма оператора присваивания + стрелочная функция , важно! важный! важный!

Оператор присваивания, написанный в классе, помещается в его собственный экземпляр, а затем метод записывается как стрелочная функция, this из стрелочной функции является объектом экземпляра, поэтому конструктор можно упростить.

(Цель написания конструктора — настроить некоторые атрибуты инициализации. Теперь напишите атрибуты как операторы присваивания и поместите их в класс, и вы получите состояние напрямую)

//1.创建组件
class Weather extends React.Component{
    
    
	//初始化状态
	state = {
    
    isHot:false,wind:'微风'}
	render(){
    
    
		const {
    
    isHot,wind} = this.state
		return <h1 onClick={
    
    this.changeWeather}>今天天气很{
    
    isHot ? '炎热' : '凉爽'}{
    
    wind}</h1>
	}
	//自定义方法————要用赋值语句的形式+箭头函数
	changeWeather = ()=>{
    
    
		const isHot = this.state.isHot
		this.setState({
    
    isHot:!isHot})
	}
}
//2.渲染组件到页面
ReactDOM.render(<Weather/>,document.getElementById('test'))

3 Один из трех основных атрибутов экземпляров компонентов: свойства

3.1 понимание реквизита

  • Каждый объект компонента будет иметь атрибут props (сокращение от properties).

  • Все свойства тегов компонентов хранятся в свойствах

3.2 Роль и внимание реквизита

  • Передача изменяющихся данных снаружи компонента внутрь компонента через атрибут метки

  • Примечание. Не изменяйте данные реквизита внутри компонента, реквизит доступен только для чтения.

  • Если входящие данные слишком длинные, полученные данные объекта могут быть записаны как {...p}входящие.

  • Вы можете ограничить входящий тип данных, если вы его не передаете, вы также можете указать значение по умолчанию

  • Добавляйте атрибуты в сам класс, а не в экземпляр класса, используйте static static

3.3 Пример кода

Компоненты класса используют свойства, самый простой способ использования

//创建组件
class Person extends React.Component{
    
    
	render(){
    
    
		// console.log(this);
		const {
    
    name,age,sex} = this.props
		return (
			<ul>
				<li>姓名:{
    
    name}</li>
				<li>性别:{
    
    sex}</li>
				<li>年龄:{
    
    age+1}</li>
			</ul>
		)
	}
}
//渲染组件到页面
ReactDOM.render(<Person name="jerry" age={
    
    19}  sex="男"/>,document.getElementById('test1'))
ReactDOM.render(<Person name="tom" age={
    
    18} sex="女"/>,document.getElementById('test2'))
//上面这样写有一些问题:信息很多要写太长,能不能批量操作
const p = {
    
    name:'老刘',age:18,sex:'女'}
// console.log('@',...p);
// ReactDOM.render(<Person name={p.name} age={p.age} sex={p.sex}/>,document.getElementById('test3'))
//此处使用赋值解构方式,使得代码更简洁,上面的语法糖,关键在于捞回来的数据要一样才能这样写
ReactDOM.render(<Person {
    
    ...p}/>,document.getElementById('test3'))
//...p在原生js本身是错误的,但是{...p}可以,相当于复制了一个对象。在react中的{}作为分隔符使用,但是我们引入了react加上babel就可以直接分解对象,也就是可以直接写...p,但是注意仅可以作为标签的属性使用,不是随便可以使用的
//对传入数据的类型进行限制,此处限制可以换成typrScript
<script type="text/javascript" src="../js/prop-types.js"></script>
Person.propTypes = {
    
    
	name:PropTypes.string.isRequired, //限制name必传,且为字符串---16版本之后不在React上面取了,引入prop-types依赖包
	sex:PropTypes.string,//限制sex为字符串
	age:PropTypes.number,//限制age为数值
	speak:PropTypes.func,//限制speak为函数
}

//不传的话,指定默认标签属性值
Person.defaultProps = {
    
    
	sex:'男',//sex默认值为男
	age:18 //age默认值为18
}
//props简写,把类型限制和默认值写在类里面
static propTypes = {
    
    
	name:PropTypes.string.isRequired, //限制name必传,且为字符串
	sex:PropTypes.string,//限制sex为字符串
	age:PropTypes.number,//限制age为数值
}

static defaultProps = {
    
    
	sex:'男',//sex默认值为男
	age:18 //age默认值为18
}

Функциональные компоненты используют реквизиты, потому что функции могут получать параметры

//创建组件
function Person (props){
    
    
	const {
    
    name,age,sex} = props
	return (
			<ul>
				<li>姓名:{
    
    name}</li>
				<li>性别:{
    
    sex}</li>
				<li>年龄:{
    
    age}</li>
			</ul>
		)
}

//渲染组件到页面
ReactDOM.render(<Person name="jerry"/>,document.getElementById('test1'))
//函数的类型限制要写在外面

4 Один из трех основных атрибутов экземпляров компонентов: refs

4.1 Понимание ссылок

Теги в компонентах могут определять ссылки для идентификации самих себя, подобно собственным идентификаторам, ссылки собирают узлы реального дома.

4.2 Пример кода

Есть проблема с ref() в строковой форме 不推荐,将被淘汰: это неэффективно.

//展示左侧输入框的数据
	showData = ()=>{
    
    
		const {
    
    input1} = this.refs
		alert(input1.value)
	}
	//展示右侧输入框的数据
	showData2 = ()=>{
    
    
		const {
    
    input2} = this.refs
		alert(input2.value)
	}
	render(){
    
    
		return(
			<div>
				<input ref="input1" type="text" placeholder="点击按钮提示数据"/>&nbsp;
				<button onClick={
    
    this.showData}>点我提示左侧的数据</button>&nbsp;
				<input ref="input2" onBlur={
    
    this.showData2} type="text" placeholder="失去焦点提示数据"/>
			</div>
		)
	}
}

Ссылка в форме обратного вызова хранит реальный узел DOM в экземпляре компонента this, а обратный вызов напрямую записывается как интровертная функция, которая не имеет никакого эффекта.

/**下面的this指的是组件实例,我直接this.input1 = c 意思是给实例上的input1赋值,之后直接通过调用打印得到*/
//回调函数的内联写法,会有问题,就是更新数据会重新调用两次函数,第一次传入null,第二次才是传入dom节点,这个是每次更新生成新的函数
//展示左侧输入框的数据
	showData = ()=>{
    
    
		const {
    
    input1} = this//在实例身上取
		alert(input1.value)
	}
	//展示右侧输入框的数据
	showData2 = ()=>{
    
    
		const {
    
    input2} = this
		alert(input2.value)
	}
	render(){
    
    
		return(
			<div>
				<input ref={
    
    c => this.input1 = c } type="text" placeholder="点击按钮提示数据"/>&nbsp;
				<button onClick={
    
    this.showData}>点我提示左侧的数据</button>&nbsp;
				<input onBlur={
    
    this.showData2} ref={
    
    c => this.input2 = c } type="text" placeholder="失去焦点提示数据"/>&nbsp;
			</div>
		)
	}
}
//回调函数写成class的绑定函数,就不会频繁调用,不会生成新的函数
saveInput = (c)=>{
    
    
	this.input1 = c;
	console.log('@',c);
}

render(){
    
    
	return(
		<div>
			<input ref={
    
    this.saveInput} type="text"/><br/><br/>
			<button onClick={
    
    this.showData}>点我提示左侧的数据</button>&nbsp;
			<input onBlur={
    
    this.showData2} ref={
    
    c => this.input2 = c } type="text" placeholder="失去焦点提示数据"/>&nbsp;
		</div>
	)
}

createRef создает контейнер ссылки最推荐的

/*React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是“专人专用”的*/
//用几个就要创建几个容器,一个容器只能放一个ref标识的节点
myRef = React.createRef()
myRef2 = React.createRef()
//展示左侧输入框的数据
showData = ()=>{
    
    
    // 取出保存在容器里的节点
	alert(this.myRef.current.value);
}
//展示右侧输入框的数据
showData2 = ()=>{
    
    
	alert(this.myRef2.current.value);
}
render(){
    
    
	return(
		<div>
             {
    
    /*把ref所在的节点存储到刚才实例身上生成的容器myRef里面*/}
			<input ref={
    
    this.myRef} type="text" placeholder="点击按钮提示数据"/>&nbsp;
			<button onClick={
    
    this.showData}>点我提示左侧的数据</button>&nbsp;
			<input onBlur={
    
    this.showData2} ref={
    
    this.myRef2} type="text" placeholder="失去焦点提示数据"/>&nbsp;
		</div>
	)
}

5 Обработка событий и сбор данных формы

5.1 Обработка событий

Укажите функцию обработчика событий по onXxxатрибуту (обратите внимание на регистр) (native: onclick, React: onClick)

  • React использует пользовательские (синтетические события, а не нативные события DOM) — для лучшей совместимости.

  • События в React обрабатываются посредством делегирования событий (делегирование самому внешнему элементу компонента) — для большей эффективности.

Получите объект элемента DOM, в котором произошло событие, через event.target ----- не злоупотребляйте ref

//不过度使用ref:发生事件的元素正好是我要操作的元素时,就可以避免使用ref(受控组件可以发生事件与操作的元素不同)
//失去焦点的时候react会帮你调用这个函数,并把事件对象event传进去
//就可以拿到发生事件的事件源event.target,event.target就是input框
showData2 = (event) => {
    
    
	alert(event.target.value);
}

render() {
    
    
	return (
		<div>
			<input ref={
    
    this.myRef} type="text" placeholder="点击按钮提示数据" />&nbsp;
			<button onClick={
    
    this.showData}>点我提示左侧的数据</button>&nbsp;
			<input onBlur={
    
    this.showData2} type="text" placeholder="失去焦点提示数据" />&nbsp;
		</div>
	)
}

5.2 Классификация компонентов формы

Управляемый компонент, dom класса ввода, будет поддерживать вещи в состоянии, когда вы их вводите, и выводит их из состояния, когда вы их используете (не пишите ref)

state = {
    
    //初始化状态
	username:'', //用户名
	password:'' //密码
}

//保存用户名到状态中
saveUsername = (event)=>{
    
    
	this.setState({
    
    username:event.target.value})
}

//保存密码到状态中
savePassword = (event)=>{
    
    
	this.setState({
    
    password:event.target.value})
}

//表单提交的回调
handleSubmit = (event)=>{
    
    
	event.preventDefault() //阻止表单提交
	const {
    
    username,password} = this.state
	alert(`你输入的用户名是:${
      
      username},你输入的密码是:${
      
      password}`)
}

render(){
    
    
	return(
		<form onSubmit={
    
    this.handleSubmit}>
			用户名:<input onChange={
    
    this.saveUsername} type="text" name="username"/>
			密码:<input onChange={
    
    this.savePassword} type="password" name="password"/>
			<button>登录</button>
		</form>
	)
}

Неконтролируемые компоненты, готовые к использованию, требуется реф.

handleSubmit = (event)=>{
    
    
	event.preventDefault() //阻止表单提交
	const {
    
    username,password} = this
	alert(`你输入的用户名是:${
      
      username.value},你输入的密码是:${
      
      password.value}`)
}
render(){
    
    
	return(
		<form onSubmit={
    
    this.handleSubmit}>
			用户名:<input ref={
    
    c => this.username = c} type="text" name="username"/>
			密码:<input ref={
    
    c => this.password = c} type="password" name="password"/>
			<button>登录</button>
		</form>
	)
}

6 Функции высшего порядка и каррирование функций

Стрелочная функция, сохраняющая входные данные в состояние в управляемом компоненте, была написана слишком много раз, если много всего, напишите кучу стрелочных функций.

Напишите функцию saveFormData('username') и сообщите ей параметры

onChange ={this.saveFormData('username')}, что означает использование возвращаемого значения saveFormData в качестве обратного вызова onChange. Было бы здорово, если бы возвращаемое значение было функцией, а возвращаемая функция - настоящим обратным вызовом
вставьте сюда описание изображения

Не говорите, писать ли круглые скобки в обратных вызовах функций, сводка такова, что функция должна быть передана XXX в качестве обратного вызова.

saveFormData — это функция высшего порядка (возвращаемое значение — это функция)

//保存表单数据到状态中
saveFormData = (dataType) => {
    
    
	return (event) => {
    
    
		//基本功 对象里面读取变量[]
		this.setState({
    
     [dataType]: event.target.value })
	}
}

render() {
    
    
	return (
		<form onSubmit={
    
    this.handleSubmit}>
			用户名:<input onChange={
    
    this.saveFormData('username')} type="text" name="username" />
			密码:<input onChange={
    
    this.saveFormData('password')} type="password" name="password" />
			<button>登录</button>
		</form>
	)
}

6.1 Функции высшего порядка

Функция является функцией высшего порядка, если она удовлетворяет любой из следующих двух спецификаций.

  • Если функция A принимает функцию в качестве параметра, то A можно назвать функцией высшего порядка.

  • Если возвращаемое значение функции A все еще является функцией, то A можно назвать функцией более высокого порядка.

Общие функции высокого порядка: Promise, setTimeout, arr.map() и т. д.

6.2 Каррирование функций

Метод продолжения возврата функции через вызов функции реализует форму кодирования функции окончательной унифицированной обработки принятых параметров.

function sum(a){
    
     return (b)=>{
    
    return c=>{
    
     return a+b+c} }}

6.3 Реализовать привязку событий без каррирования функций

Используйте функцию обратного вызова напрямую, потому что она сама возвращает функцию

<input onChange={
    
    event => this.saveFormData('username',event) } type="text" name="username"/>

7 жизненный цикл

Компоненты проходят определенные этапы от создания до смерти.

Компоненты React содержат ряд функций-ловушек (функций обратного вызова жизненного цикла), которые будут вызываться в определенные моменты времени.

Когда мы определяем компоненты, мы будем выполнять определенную работу в определенных функциях обратного вызова жизненного цикла.

7.1 Жизненный цикл React (старый)

вставьте сюда описание изображения

Порядок вызова каждого хука жизненного цикла

Фаза инициализации : запускается ReactDOM.render()

  • конструктор()

  • компонентWillMount()

  • оказывать()

  • компонентDidMount() ==>常用

В общем, componentDidMount()сделайте некоторую инициализацию в хуке, например: запустите таймер, отправьте сетевые запросы, подпишитесь на сообщения и т. д.

Фаза обновления : запускается this.setState() внутри компонента или рендеринга родительского компонента.

Один из трех маршрутов: маршрут setState()

  • shouldComponentUpdate() Компонент должен быть обновлен. Если вы его не напишете, нижний слой автоматически заполнит один, и возвращаемое значение будет true. Напишите его сами и не забудьте вернуть значение

  • компонент componentWillUpdate() будет обновлен

  • render() ===> 必须使用один из

  • компонент componentDidUpdate() будет обновлен

Второй из трех маршрутов: маршрут forceUpdate():

forceUpdate() Принудительное обновление: если вы хотите обновить компонент без изменения состояния, пропустите shouldComponentUpdate()

Третий из трех маршрутов: рендеринг родительского компонента

Напишите конструктор componentWillReceiveProps в подкомпоненте, что означает, что подкомпонент будет вызываться, когда получит переданные параметры (примечание: он не будет вызываться при первой передаче!!!), а также может получать пропсы параметры

Размонтировать компонент : активируется ReactDOM.unmountComponentAtNode( 卸载节点上的组件).

  • componentWillUnmount() ===> 常用компонент будет размонтирован

Как правило, в этом хуке сначала делайте некоторые вещи, такие как: закрытие таймера, отписка и т. д.

7.2 Жизненный цикл React (новое)

вставьте сюда описание изображения

Три конструкции UNSAFE_начинаются с: UNSAFE_compinentWillMount(), UNSAFE_componentWillReceiveProps(),UNSAFE_componentWillUpdate()

Обозначение: конструкторы с UNSAFE_ захотят добавить, за исключением того, что они будут удалены (эти три хука являются устаревшими).

Зачем добавлять эти префиксы: Многие неправильно понимают и злоупотребляют, особенно когда новый асинхронный рендеринг выпускается позже, это приведет к ошибкам. Добавление префикса увеличивает стоимость использования

вставьте сюда описание изображения

Резюме: в старом жизненном цикле будут отброшены три хука, а в новом добавятся 2 хука.

Фаза инициализации : активируется ReactDOM.render() — начальный рендеринг

  • конструктор()

  • getDerivedStateFromProps() Получить производное состояние из реквизита ===>不常用

getDerivedStateFromProps() не для экземпляров, поэтому он определен как статический метод в классе и должен возвращать значение: объект состояния или ноль, а параметры, которые могут быть получены, - это свойства и состояние.

А если возвращается статусный объект, то обновление не сработает, а возвращаемый объект является основным, если возвращаемый объект пишется не сам по себе, а полученный реквизит, то это объяснение получения производного состояния из реквизита, простыми словами После использования этого хука значение состояния зависит от переданного в реквизите и влияет на обновление

  • оказывать()

  • компонентDidMount() ====>常用

Фаза обновления : запускается this.setState() внутри компонента или рендеринга родительского компонента.

  • getDerivedStateFromProps() Получить производное состояние от Props

  • shouldComponentUpdate() Компонент должен быть обновлен

  • оказывать()

  • getSnapshotBeforeUpdate() Сделайте снимок перед обновлением

getSnapshotBeforeUpdate() должен возвращать значение моментального снимка или null, любое значение может быть использовано в качестве значения моментального снимка, возврат к componentDidUpdate

Смысл получения снимка: щелкните несколько фотографий, чтобы выполнить некоторые операции до того, как компонент будет обновлен на странице

вставьте сюда описание изображения

  • компонентDidUpdate()

componentDidUpdate() получает три параметра (preProps, preState, snapshotValue), а последний параметр передается из хука getSnapshotBeforeUpdate.

Размонтировать компонент : активируется ReactDOM.unmountComponentAtNode()

  • компонентWillUnmount() ===>常用

7.3 Важные крючки

  • render: инициализация рендеринга или обновление вызовов рендеринга.

  • componentDidMount() : Включить мониторинг: отправить запрос ajax

  • componentWillUnmount(): выполнить некоторые отделочные работы, например: очистить таймер

7.4 Хуки, которые скоро устаревают

  • компонентWillMount

  • компонентWillReceiveProps

  • компонентWillUpdate

ps: При использовании сейчас будет предупреждение, а версия в будущем может нуждаться в префиксе UNSAFE_, а в будущем от нее могут вообще отказаться, поэтому не рекомендуется использовать

Предполагается, что команда React считает, что увеличение стоимости использования косвенно повлияет на нас, давайте адаптируемся к новому хуку, поэтому добавьте это

8 ключей в React/VUE

Классические вопросы на собеседовании:

  • Какова функция ключа в React/VUE (каков внутренний принцип ключа)

  • Почему лучше не использовать индекс для ключа при обходе списка

8.1 Роль ключа в виртуальном DOM

Проще говоря: ключ — это идентификатор виртуального DOM-объекта, и ключ играет чрезвычайно важную роль в обновлении отображения.

Подробно: при изменении данных в состоянии react будет генерировать по ним 新数据, 新的虚拟DOMа потом react сравнивать 新虚拟DOMс 旧虚拟DOMdiff.Правила сравнения такие:

  • Тот же ключ, что и новый виртуальный DOM, находится в старом виртуальном DOM:

      若虚拟DOM中内容没变,直接使用之前的真实DOM
    
      若虚拟DON中的内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
    
  • Тот же ключ, что и новый виртуальный DOM, не был найден в старом виртуальном DOM:

      根据数据创建新的真实DOM,随后渲染到页面
    

8.2 Возможные проблемы, вызванные использованием индекса в качестве ключа

  • Если вы выполняете операции над данными: добавляете в обратном порядке, удаляете в обратном порядке и т. д.:

      会产生没有必要的真实DOM更新 ==>界面效果没问题,但是效率低
    
  • Если структура также содержит DOM входного класса

      会产生错误DOM更新 ===>界面有问题
    
  • Уведомление:

      如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的
    

8.3 Как выбрать ключ во время разработки

  • В качестве ключа лучше всего использовать уникальный идентификатор каждого фрагмента данных, например, идентификатор, номер мобильного телефона, идентификационный номер, номер студента и т. д.

  • Если установлено, что это просто отображение стихов, можно также использовать указатель

//慢动作回放----使用index索引值作为key
		初始数据:
				{
    
    id:1,name:'小张',age:18},
				{
    
    id:2,name:'小李',age:19},
		初始的虚拟DOM<li key=0>小张---18<input type="text"/></li>
				<li key=1>小李---19<input type="text"/></li>

		更新后的数据:
				{
    
    id:3,name:'小王',age:20},
				{
    
    id:1,name:'小张',age:18},
				{
    
    id:2,name:'小李',age:19},
		更新数据后的虚拟DOM<li key=0>小王---20<input type="text"/></li>
				<li key=1>小张---18<input type="text"/></li>
				<li key=2>小李---19<input type="text"/></li>

-----------------------------------------------------------------

//慢动作回放----使用id唯一标识作为key

		初始数据:
				{
    
    id:1,name:'小张',age:18},
				{
    
    id:2,name:'小李',age:19},
		初始的虚拟DOM<li key=1>小张---18<input type="text"/></li>
				<li key=2>小李---19<input type="text"/></li>

		更新后的数据:
				{
    
    id:3,name:'小王',age:20},
				{
    
    id:1,name:'小张',age:18},
				{
    
    id:2,name:'小李',age:19},
		更新数据后的虚拟DOM<li key=3>小王---20<input type="text"/></li>
				<li key=1>小张---18<input type="text"/></li>
				<li key=2>小李---19<input type="text"/></li>

Supongo que te gusta

Origin blog.csdn.net/m0_55644132/article/details/127696715
Recomendado
Clasificación