Непонятные моменты для начинающих, чтобы научиться реагировать (2)

внешний интерфейс JavaScript

Друзья, которые не читали первую статью, могут сначала прочитать первую статью:Непонятные моменты для начинающих, чтобы научиться реагировать (1)

Реакция на первую статью тоже была хорошей.Многие новички нашли ее очень полезной и ответили на свои давние сомнения.На самом деле, первая статья была довольно простой, в основном потому, что синтаксис ES6 и JSX не имели глубокого понимания.

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

Давайте начнем!

Зачем вызывать метод для привязки этого

Необходимые знания:Глубокое понимание этого в JavaScript

Я считаю, что когда я впервые написал React, многие из моих друзей могли написать такой код:

class Foo extends React.Component {
  handleClick () {
    this.setState({ xxx: aaa })
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    )
  }
}

отчет об открытииthisдаundefinedнеправильно, тогда вы можете больше запутаться в обработке событий, а затем перейти на официальный сайтобработка событийЕсть следующий отрывок:

Вы должны быть осторожны с обратными вызовами JSXthis, в JavaScript методы класса по умолчанию несвязыватьthis. Если вы забыли привязатьthis.handleClickи передал его вonClick, когда вы вызываете эту функциюthisценностьundefined.

Это не специфичное для React поведение;Как работают функции JavaScriptСвязанный. Как правило, если вы не добавляете после метода(),НапримерonClick={this.handleClick}, вы должны выполнить привязку для этого методаthis.

Затем после того, как вы прочитали примеры и предложения на официальном сайте, вы знаете, что вам нужно привязать функцию обработчика событийthisЭто можно решить, например, так:

class Foo extends React.Component {
  handleClick () {
    this.setState({ xxx: aaa })
  }

  render() {
    return (
      <button onClick={this.handleClick.bind(this)}>
        Click me
      </button>
    )
  }
}

Но, может быть, вы не задумывались, зачем вам это нужно? Если вы этого не понимаете, основа js не заложена.

Как React обрабатывает события?

Давайте сначала разберемся, как React обрабатывает события.

События React являются синтетическими событиями, а внутренние принципы очень сложны. Здесь я представлю только ключевые принципы, которые можно использовать для ответа на этот вопрос (я должен написать принцип событий реакции позже, так что следите за обновлениями).

Как упоминалось в предыдущей статье, jsx на самом делеReact.createElement(component, props, …children)Синтаксический сахар, предоставляемый функцией, затем этот код jsx:

 <button onClick={this.handleClick}>
     Click me
 </button>

будет преобразовано в:

React.createElement("button", {
     onClick: this.handleClick
}, "Click me")

Поймите вышеизложенное, а затем просто поймите, как React обрабатывает события.mount) и обновить (update), передать событие черезaddEventListenerединая регистрация вdocument, то будет пул событий, в котором хранятся все события, при срабатывании события проходитdispatchEventДелайте рассылку событий.

Таким образом, вы можете просто понять, что, в конце концов,this.handleClickбудет вызываться как функция обратного вызова.

Разберитесь с этим, а потом посмотрите, почему пропадает callback-функцияthis.

этот краткий обзор

Внутри функции,thisЗначение зависит от того, как была вызвана функция.

Если вы не можете понять приведенное выше предложение, то вам может понадобиться остановиться и прочитать статью, чтобы проверить соответствующую информацию, иначе вы можете не понять следующее, если вам лень, посмотрите подготовленную для васMDNБар.

Благодаря приведенному выше введению в обработку событий для имитации функции рендеринга компонента класса это немного похоже на это:

class Foo {
  sayThis () {
    console.log(this); // 这里的 `this` 指向谁?
  }
  
  exec (cb) {
    cb();
  }
  
  render () {
    this.exec(this.sayThis);
  }
}

var foo = new Foo();
foo.render(); // 输出结果是什么?

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

Тогда вы можете спросить: **Почему React автоматически не интегрирует привязку в метод рендеринга?** Привяжите ее, когда exec вызывает обратный вызов, например:

class Foo {
  sayThis () {
    console.log(this); // 这里的 `this` 指向谁?
  }

 exec (cb) {
   cb.bind(this)();
 }

 render () {
   this.exec(this.sayThis);
 }
}

var foo = new Foo();
foo.render(); // 输出结果是什么?

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

Сравнение четырех видов обработки событий

Есть несколько способов написать обработку событий, давайте сравним:

1. Напрямую привязать этот тип

Как и в начале статьи, привяжите это прямо к событию

class Foo extends React.Component {
  handleClick () {
    this.setState({ xxx: aaa })
  }

  render() {
    return (
      <button onClick={this.handleClick.bind(this)}>
        Click me
      </button>
    )
  }
}

преимущество: Писать легко, эту логику можно написать на одном дыхании, не переводя курсор в другие места.

недостаток: Производительность не очень.Этот метод такой же, как и внутренняя привязка реакции.Каждый раз при выполнении рендера будет выполняться привязка, и если есть два элемента с одинаковой функцией обработки событий, то привязка все равно будет быть выполнено, что потребует больше написания кода, и привязки дважды, производительность не очень хорошая. (На самом деле эта производительность часто не является узким местом производительности. Если вы чувствуете себя комфортно, то писать так вполне нормально)

2. Тип ручной привязки конструктора

class Foo extends React.Component {
  constuctor(props) {
    super(props)
    this.handleClick = this.handleClick.bind(this)
  }
  handleClick () {
    this.setState({ xxx: aaa })
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    )
  }
}

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

недостаток:Явных недостатков нет.Если хочешь сказать, то слишком некрасиво, а то не ладится (думаю, некрасиво, можно просто написать, если считаешь, что некрасиво).

3. Тип функции стрелки

class Foo extends React.Component {
  handleClick () {
    this.setState({ xxx: aaa })
  }

  render() {
    return (
      <button onClick={(e) => this.handleClick(e)}>
        Click me
      </button>
    )
  }
}

преимущество:Удобно, приятно.

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

4. тип полей публичного класса

этоclass fieldsОн все еще находится в экспериментальной стадии и, насколько мне известно, еще не включен в стандарт.здесь.

class Foo extends React.Component {
  handleClick = () => {
    this.setState({ xxx: aaa })
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    )
  }
}

преимущество:Хорошо выглядит и хорошо работает.

недостаток:Явного минуса нет.Если настаивать, то возможно придется установить еще одинПлагин Бабельдля поддержки этого синтаксиса.

Суммировать

Я обычно использую эти четыре способа написания, и я сделал простое сравнение различных способов написания с точки зрения эстетики, производительности и удобства кода. На самом деле проблем в использовании каждого метода в проекте нет.Производительность в принципе можно не учитывать.Эстетика и простота использования больше субъективны,так что в общем-то это зависит от предпочтений каждого.Если вы настаиваете на том, чтобы рекомендовать его, я все равно рекомендую.Четвертый способ написания красивый и на производительность не влияет.

Почему setState вместо прямого this.state.xx = oo

Этот вопрос возник, когда бэкенд нашей компании писал React, почему нельзя напрямую модифицировать состояние, нужно setState. Я думаю, что могут быть такие сомнения при переходе с vue на React, потому что состояние модификации vue напрямую меняется.

Если мы поймем принцип setState, мы сможем ответить на этот вопрос.this.stateЗначение и, что наиболее важно, запускает механизм обновления React, который будет различаться, а затем обновлять часть патча до реального dom.

если вы напрямуюthis.state.xx == ooЕсли это так, значение состояния действительно изменится, но изменение не будет запускать обновление интерфейса пользователей, поэтому он не управляет данными.

Так почему же Vue может напрямую изменять данные для запуска обновлений пользовательского интерфейса? Поскольку Vue будет собирать эти данные при создании пользовательского интерфейса и переписывать установщик свойств доступа к этим данным, обновление пользовательского интерфейса будет запускаться в этом переписанном методе. Если вы хотите узнать больше о принципах vue, вы можете купить Ranmo'sАнализ внутренней работы Vue.js.

Если вы не понимаете свойства аксессора, вы можете прочитать эту статью:Глубокое понимание объектов в JS

Является ли setState синхронным или асинхронным, связанным с этим проблемами

1. Является ли setState синхронным или асинхронным?

Мой ответ - выполнять код процесса синхронно,Просто последовательность вызова синтетической функции события и ловушки находится перед обновлением, так что обновленное значение не может быть сразу получено в синтетической функции события и ловушки, что формирует так называемую "асинхронность",такпоказыватьИногда синхронный, иногда «асинхронный».

2. Когда синхронно, а когда асинхронно?

Он «асинхронен» только в синтетических событиях и функциях ловушек и синхронен в собственных событиях и собственных API, таких как setTimeout/setInterval. Можно просто понять, что функция, управляемая React, будет показывать «асинхронность», и наоборот, она будет синхронной.

3. Тогда почему возникает асинхронная ситуация?

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

4. Как точно получить обновленное состояние в функции, выражающей асинхронность?

через второй параметрsetState(partialState, callback)Обратный вызов получает обновленный результат.

Или вы можете выразить синхронизацию, передав функцию в setState:

this.setState((state) => {
	return { val: newVal }
})

5. Вот показал асинхронный принцип вроде как это?

Конечно, недостаточно места, чтобы поговорить непосредственно с исходным кодом, вы можете увидеть эту статью:Вы действительно понимаете setState?.

Я буду использовать здесь самый простой язык, чтобы вы поняли: в реализации функции setState в React она будет оцениваться в соответствии с переменной isBatchingUpdates (по умолчанию — false), следует ли обновлять это состояние напрямую или поместить его в очередь для обновления позже. Затем есть функция batchedUpdate, которая может изменить isBatchingUpdates на true.Когда React вызывает обработчик события или перед функцией жизненного цикла, будет вызываться функция batchedUpdate.В этом случае setState не будет обновлять this.state синхронно, а будет помещен в очередь обновлений Последующие обновления внутри.

Таким образом, вы можете понять, почему вызов this.state в нативных событиях и setTimeout/setinterval будет обновляться синхронно, потому что React, вызываемый через эти функции, не может вызвать функцию batchedUpdate, чтобы установить для isBatchingUpdates значение true, тогда по умолчанию, когда setState имеет значение false, тогда он будет обновлен синхронно.

наконец

setState — очень важный метод React, и стоит изучить его принципы.

Справочная статья

постскриптум

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


Я Тао Вэн, фронтендер, который любит думать. Если вы хотите узнать больше о фронтенде, пожалуйста, обратите внимание на мой официальный аккаунт: «Фронтенд Таоюань». Если вы хотите присоединиться к группе по обмену , подпишитесь на официальную учетную запись и ответьте на «WeChat», чтобы привлечь вас. группа

Категории