Неужели контролируемые и неконтролируемые компоненты так сложно понять? (Подробное объяснение фактического случая React)

JavaScript React.js
Неужели контролируемые и неконтролируемые компоненты так сложно понять? (Подробное объяснение фактического случая React)

предисловие

Ты с нетерпением ждешь мира, надеюсь, у тебя нетbug. Всем привет! Я Лин Дуан.

У меня в последнее время мало что выводится😂, то ли стоп-уведомление, то ли"软文", все еще немного смущен. Это не большая проблема, я сказал (пи) Цянь (толстый) слегка 😄.

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

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

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

(Да, длинное здесь — это то, что вы считаете длинным, а короткое — это не то, что вы считаете коротким...)

Ладно👌, без скина😁, давайте посмотрим, чему вы можете научиться, прочитав эту статью:

  • Основные понятия управляемых компонентов
  • выбрать контролируемый компонент
  • Динамический корпус компонента с контролируемой формой
  • неконтролируемые компоненты
  • Специальная файловая метка

текст

Основные понятия управляемых компонентов

Из названий мы можем догадаться, что означают эти два слова:

  • Контролируемые компоненты: Компоненты под нашим контролем
  • Неконтролируемые компоненты: Компоненты, которые не находятся под нашим контролем.

(Разве это не вздор Тимо...)

Агем, хорошо, что вы имеете в виду под контролируемым и неконтролируемым здесь? На самом деле, мыКонтроль над состоянием компонента, может ли его значение быть установлено только пользователем, не контролируется кодом.

мы знаем, что вReactопределяетinputполе ввода, в нем нет чего-то вродеVueвнутриv-modelЭто двусторонняя привязка. Другими словами, у нас нет поля ввода команды и данных, которое может объединять пользовательский ввод в поле ввода, а затем обновлять синхронизацию данных.

Как этот случай:

class TestComponent extends React.Component {
  render () {
    return <input name="username" />
  }
}

Когда пользователь вводит контент в поле ввода на интерфейсе, он поддерживает"state", чтобы он мог сделать это сам на основе ввода пользователяUIобновление на . (этоstateне то, что мы обычно видимthis.state, но абстрагируется от каждого элемента формыstate)

Подумайте, что мы можем сделать, если хотим контролировать содержимое поля ввода в это время? Ну... содержимое поля ввода зависит отinputсерединаvalueимущество, то мы можемthis.stateопределить именованныйusernameсвойства и воляinputВверхvalueУказано как это свойство:

class TestComponent extends React.Component {
  constructor (props) {
    super(props);
    this.state = { username: 'lindaidai' };
  }
  render () {
    return <input name="username" value={this.state.username} />
  }
}

Но тогда вы найдетеinputСодержание - только чтение, потому чтоvalueбудет нашимthis.state.usernameконтролируется, когда пользователь вводит новый контент,this.state.usernameне обновляется автоматически, поэтомуinputСодержимое внутри не изменится.

ха-ха, как вы уже поняли, мы можем использоватьonChangeсобытия для прослушивания изменений во входном содержимом и использованияsetStateвозобновитьthis.state.username:

class TestComponent extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
      username: "lindaidai"
    }
  }
  onChange (e) {
    console.log(e.target.value);
    this.setState({
      username: e.target.value
    })
  }
  render () {
    return <input name="username" value={this.state.username} onChange={(e) => this.onChange(e)} />
  }
}

Теперь независимо от того, что пользователь вводитstateа такжеUIбудет обновлен, и мы сможем использовать его в другом месте компонента.this.state.usernameполучитьinputконтент также может быть доступен черезthis.setState()Модифицироватьinputсодержание в.

Хорошо 👌, а теперь посмотримУправляемые компонентыОпределение:

В элементах формы HTML они обычно поддерживают наборstate, и сделать это самостоятельно с пользовательским вводомUI上的更新,这种行为是不被我们程序所管控的。 И еслиReactвнутреннийstateАтрибуты и значения элементов формы устанавливают зависимости, а затем передаютonChangeсобытие иsetState()комбинированное обновлениеstateАтрибуты, вы можете управлять работой формы в процессе пользовательского ввода. одеялоReactЭлементы ввода формы, управляющие значением таким образом, называютсяУправляемые компоненты.

(Ну, я думаю, приведенное выше резюме 👆 можно использовать в интервью)

выбрать контролируемый компонент

оставайся на вершинеinputЯ продемонстрировал всем самый простой управляемый компонент, по сути, он похож на другие элементы формы, которые могут быть просто другими именами атрибутов и событиями.

НапримерinputТипtextИспользуемый элемент формы:

  • value
  • onChange

дляtextareaЭтикетка также используется такvalueа такжеonChange:

<textarea value={this.state.value} onChange={this.handleChange} />

радио выбрать

дляselectДля элементов формы,ReactМожно и нативно превратить в управляемый компонентHTMLЕсть некоторые отличия.

В нативном режиме мы по умолчаниюselectопция проверена с помощью isselected, например:

<select>
  <option value="sunshine">阳光</option>
  <option value="handsome">帅气</option>
  <option selected value="cute">可爱</option>
  <option value="reserved">高冷</option>
</select>

Дать"可爱"Опция установленаselected, он выбран по умолчанию.

Но если вы используетеReactКонтролируемые компоненты доставляют меньше хлопот, поскольку позволяютselectиспользуется на этикеткеvalueсвойства для управления тем, что выбрано. В данном случае нам тоже удобнее, нужно только обновлять его в корневом теге после каждого повторного выбора пользователем, как в этом случае 🌰:

class SelectComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { value: 'cute' };
  }
  handleChange(event) {
    this.setState({value: event.target.value});
  }
  handleSubmit(event) {
    alert('你今日相亲对象的类型是: ' + this.state.value);
    event.preventDefault();
  }
  render() {
    return (
      <form onSubmit={(e) => this.handleSubmit(e)}>
        <label>
          你今日相亲对象的类型是:
          <select value={this.state.value} onChange={(e) => this.handleChange(e)}>
            <option value="sunshine">阳光</option>
            <option value="handsome">帅气</option>
            <option value="cute">可爱</option>
            <option value="reserved">高冷</option>
          </select>
        </label>
        <input type="submit" value="提交" />
      </form>
    );
  }
}
export default SelectComponent;

можно ли увидетьinputТипtextЭлементы управления по-прежнемуtextarea、selectв реализацииУправляемые компонентыЭто почти то же самое.

большой выбор

Большой выборselectЕсли выбрано контраст, только эти два изменения:

  • ДатьselectНастройки ярлыкаmultipleсобственностьtrue
  • selectЭтикеткаvalueСвязанное значение представляет собой массив

Давайте просто напишем небольшой случай здесь:

class SelectComponent extends React.Component {
  constructor(props) {
    super(props);
    // this.state = { value: 'cute' };
    this.state = { value: ['cute'] };
  }

  handleChange(event) {
    console.log(event.target.value)
    const val = event.target.value;
    const oldValue = this.state.value;
    const i = this.state.value.indexOf(val);
    const newValue = i > -1 ? [...oldValue].splice(i, 1) : [...oldValue, val];
    this.setState({value: newValue});
  }

  handleSubmit(event) {
    alert('你今日相亲对象的类型是: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={(e) => this.handleSubmit(e)}>
        <label>
          你今日相亲对象的类型是:
          <select multiple={true} value={this.state.value} onChange={(e) => this.handleChange(e)}>
            <option value="sunshine">阳光</option>
            <option value="handsome">帅气</option>
            <option value="cute">可爱</option>
            <option value="reserved">高冷</option>
          </select>
        </label>
        <input type="submit" value="提交" />
      </form>
    );
  }
}
export default SelectComponent;

(Но, оставаясь на Mac, Chrome, тестирующий этот множественный выбор, кажется проблематичным)

Динамический корпус компонента с контролируемой формой

Выше 👆 мы реализовали несколько простых случаев контролируемых компонентов, а затем воспроизвели чуть более сложный.

Давайте сначала посмотрим на наши потребности:

Реализуйте компонент, передайте следующий массив и автоматически отобразите форму:

(CInputпредставляет поле ввода,CSelectпредставляет поле выбора)

// 决定表单的结构
const formConfig = [
  {
    Component: CInput,
    label: '姓名',
    field: 'name',
  },
  {
    Component: CSelect,
    label: '性别',
    field: 'sex',
    options: [{ label: '男', value: 'man' }, { label: '女', value: 'woman' }]
  }
]
// 决定表单的内容
this.state = {
  name: '霖呆呆',
  sex: 'man'
}

Эффект:

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

  • formConfigОпределяет структуру формы, то есть определяет, какие элементы будут в форме

  • this.stateопределяет значение каждого элемента в форме, связанное сformConfigзависит отformConfigразличныхfieldполе для установления связи.

Зная вышеизложенное 👆, мы можем быстро написать общий вид этого компонента динамической формы:

(Мы назвали этот компонент какformComponentНу сосредоточься наrenderчасть)

import React, { Component } from 'react';
import { CInput, CSelect } from './components'
export default class FormComponent extends Component {
	constructor (props) {
    super(props);
    this.state = {
      name: '霖呆呆',
      sex: 'man'
    }
  }
  formConfig = [
    {
      Component: CInput,
      label: '姓名',
      field: 'name',
    },
    {
      Component: CSelect,
      label: '性别',
      field: 'sex',
      options: [{ label: '男', value: 'man' }, { label: '女', value: 'woman' }]
    }
  ]
  render () { // 重点在这
    return (
      <form style={{marginTop: '50px'}}>
        {
          this.formConfig.map((item) => { // 枚举formConfig
            const { Type, field, name } = item;
            const ControlComponent = item.Component; // 提取Component
            return (
              <ControlComponent key={field} />
            )
          })
        }
      </form>
    )
  }
}

можно увидеть,renderВот некоторые из вещей, которые мы делаем:

  • перечислитьformConfigмножество
  • извлечь каждыйComponent, присвоеноControlComponent
  • визуализировать каждый элементComponent

ControlComponentСмысл переменной в том, чтобы сказатьReact, какой компонент нужно отрендерить, еслиitem.ComponentдаCInput, то окончательный рендеринг<CInput />.

Это гарантирует, чтоformConfigКаждый элемент формы в массиве визуализируется, но эти элементы формы по-прежнему находятся вне нашего контроля, нам нужно использовать то, что мы узнали ранее.valueа такжеonChangeи каждыйControlComponentСделайте соединение, например:

<ControlComponent
  key={field}
  name={field}
  value={this.state[field]}
  onChange={this.onChange}
  {...item}
/>

мы кладемthis.state[field]установлен вvalueвверх, положитьthis.onChangeустановлен вonChangeхарактеристики. (Как вы понимаете,CInputа такжеCSelectдоступные компонентыthis.propsдля получения входящих свойств, напримерthis.props.value)

Тогда на этот разvalueУстановлено, что он изготовленthis.state[field]решил, еслиfieldда"sex"если,valueЗначение"man".

так что посмотриonChangeКак написать метод:

onChange = (event, field) => {
  const target = event.target;
  this.setState({
    [field]: target.value
  })
}

Этот метод на самом деле очень прост, он принимаетeventа такжеfield,существуетeventВы можете получить значение, введенное/выбранное пользователем.

Хорошо 👌, давайте быстро посмотримCInputа такжеCSelectКак этого добиться:

components/CInput.jsx:

import React, { Component } from 'react';

export default class CInput extends Component {
  constructor (props) {
    super(props);
  }
  render () {
    const { name, field, value, onChange } = this.props;
    return (
      <>
        <label>
          {name}
        </label>
        <input name={field} value={value} onChange={(e) => onChange(e, field)} />
      </>
    )
  }
}

components/CSelect.jsx:

import React, { Component } from 'react';

export default class CSelect extends Component {
  constructor (props) {
    super(props);
  }
  render () {
    const { name, field, options, value, onChange } = this.props;
    return (
      <>
        <label>
          {name}
        </label>
        <select name={field} value={value} onChange={(e) => onChange(e, field)}>
          {options.length>0 && options.map(option => {
            return <option key={option.value} value={option.value}>{option.label}</option>
          })}
        </select>
      </>
    )
  }
}

Конечно, то, что здесь продемонстрировано, — это просто реализация динамической формы, если вы хотите реализовать ее в своем проекте, это намного сложнее, чем это.

неконтролируемые компоненты

Вышеприведенный 👆 показывает вам некоторые основные понятия и связанные с ними операции управляемых компонентов.Для управляемых компонентов нам необходимо状态更新(Напримерthis.state.username) написать事件处理程序(Напримерthis.setState({ username: e.target.value })).

Тогда есть другой сценарий: мы просто хотим получить значение элемента формы, и нам все равно, как оно изменится. Есть ли у нас способ справиться с этим сценарием🤔️?

Хорошо...inputярлык это на самом деле тожеDOMэлемент, то можем ли мы получитьDOMИнформация об элементе способ получить значение элемента формы? то есть использоватьref.

Так же, как этот случай ниже:

import React, { Component } from 'react';

export class UnControll extends Component {
  constructor (props) {
    super(props);
    this.inputRef = React.createRef();
  }
  handleSubmit = (e) => {
    console.log('我们可以获得input内的值为', this.inputRef.current.value);
    e.preventDefault();
  }
  render () {
    return (
      <form onSubmit={e => this.handleSubmit(e)}>
        <input defaultValue="lindaidai" ref={this.inputRef} />
        <input type="submit" value="提交" />
      </form>
    )
  }
}

После ввода содержимого в поле ввода нажмите кнопку отправки, мы можем пройтиthis.inputRefуспешно получилinputизDOMИнформация о свойствах, включая введенные пользователем значения, поэтому нам не нужно поддерживать отдельное состояние для каждого элемента формы, как для контролируемого компонента.

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

тег файла специального файла

Также вinputЕсть и частный случай, т.fileТип контроля формы.

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

Например, теперь я хочу управлять им с помощью обновлений состояния:

import React, { Component } from 'react';

export default class UnControll extends Component {
  constructor (props) {
    super(props);
    this.state = {
      files: []
    }
  }
  handleSubmit = (e) => {
    e.preventDefault();
  }
  handleFile = (e) => {
    console.log(e.target.files);
    const files = [...e.target.files];
    console.log(files);
    this.setState({
      files
    })
  }
  render () {
    return (
      <form onSubmit={e => this.handleSubmit(e)}>
        <input type="file" value={this.state.files} onChange={(e) => this.handleFile(e)} />
        <input type="submit" value="提交" />
      </form>
    )
  }
}

После выбора файла я попытался использоватьsetStateЧтобы обновить, результат - ошибка:

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

import React, { Component } from 'react';

export default class FileComponent extends Component {
  constructor (props) {
    super(props);
    this.fileRef = React.createRef();
  }
  handleSubmit = (e) => {
    console.log('我们可以获得file的值为', this.fileRef.current.files);
    e.preventDefault();
  }
  render () {
    return (
      <form onSubmit={e => this.handleSubmit(e)}>
        <input type="file" ref={this.fileRef} />
        <input type="submit" value="提交" />
      </form>
    )
  }
}

получено здесьfilesЭто массив, конечно, если вы не включаете множественный выбор, длина этого массива всегда1, очень просто открыть множественный выбор, просто добавьтеmultipleсвойства могут быть:

<input type="file" multiple ref={this.fileRef} />

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

Ну... это, по официальным словам React, рекомендуется использовать большую часть времени受控组件реализовать форму, потому что в контролируемом компоненте данные формыReactОб этом позаботится компонент; конечно, если вы выберете受受控组件Если данные формыDOMразобраться с собой.

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

послесловие

Вы с нетерпением ждете мира, и я надеюсь, что у вас нет багов. Эта статья представлена ​​здесь.

В основном, чтобы представить разницу и использование элементов управления и компонентов, не являющихся элементами управления, и, наконец,"重操旧业"Начала писать статью, а сегодня неожиданно для себя обнаружила, что полугодовой итог Nuggets действительно в списке.Еще раз спасибо за щедрый лайк ❤️, ха-ха, я верю, что всем будет становиться все лучше и лучше!

Парень, которому нравится «Лин Дайдай», также надеется подписаться на публичный аккаунт Лин Дайдай LinDaiDai.

(Поскольку в последнее время я не могу опубликовать QR-код, извините за всех...)

Время от времени я буду обновлять некоторый внешний контент знаний и свои собственные оригинальные статьи🎉

Ваша поддержка - главная мотивация для меня продолжать творить 😊.

связанное предложение:

"Самый подробный учебник по bpmn.js во всей сети"

«[Предлагаемое изменение] Прочитав это, вы все еще не понимаете Вавилон, я пришлю вам маску»

«[Рекомендуемые звезды] Подойдите к концу 45 вопросов интервью Promise (1,1 Вт слов, тщательно организованных)»

«[Предложение👍] Давайте продолжим с еще 40 вопросами из этого интервью (1,2 Вт сортировки слов вручную)»

«[Почему не Sanlian] Вопросы о наследовании JS, которые проще, чем наследование семейного бизнеса — инкапсуляция (тест коровьего ножа)»

«[Почему не Sanlian] Ответив на эти 48 вопросов, я полностью понимаю наследование JS (слова 1.7w содержат симпатию — вернитесь к оригиналу)»

«Резюме 128 вопросов в недавнем интервью Лин (включая очень подробные ответы) | Техническое эссе Nuggets»