От автора: React ref позволяет получить доступ к узлам DOM непосредственно внутри React. Это полезно в ситуациях, когда, например, вы хотите изменить дочерний элемент компонента. Предположим, вы хотите изменить значение элемента input, но без использования свойства или повторного рендеринга всего компонента. Это то, что мы рассмотрим в этом посте.
Как создать ref
createRef() — это новый API, который поставляется с React 16.3. Вы можете создать ref, вызвав React.createRef() и связав с ним элемент React, используя атрибут ref для элемента.
class Example extends React.Component { constructor(props) { super(props) // Create the ref this.exampleRef = React.createRef() } render() { return ( <div> // Call the ref with the `ref` attribute <input type="text" ref={this.exampleRef} /> </div> ) } }
Мы можем «ссылаться» на узел ref, созданный в методе рендеринга, с доступом к текущему атрибуту ref. В приведенном выше примере это будет this.exampleRef.current. Вот еще один пример:
class App extends React.Component { constructor(props) { super(props) // Create the ref this.textInput = React.createRef(); this.state = { value: '' } } // Set the state for the ref handleSubmit = e => { e.preventDefault(); this.setState({ value: this.textInput.current.value}) }; render() { return ( <div> <h1>React Ref - createRef</h1> // This is what will update <h3>Value: {this.state.value}</h3> <form onSubmit={this.handleSubmit}> // Call the ref on <input> so we can use it to update the <h3> value <input type="text" ref={this.textInput} /> <button>Submit</button> </form> </div> ); } }
Как может происходить общение между дочерним компонентом и элементом, содержащим ref.
Это компонент, который отображает текст, поле ввода и кнопку. Параметр ref создается в конструкторе и затем привязывается к элементу ввода при его рендеринге. Когда кнопка нажата, значение, представленное элементом ввода (с привязанным к нему ref), используется для обновления состояния текста (содержащегося в теге H3). Мы используем this.textInput.current.value для доступа к значению, и новое состояние затем отображается на экране.
Передача функции обратного вызова в ref
React позволяет создать ref, передав функцию обратного вызова атрибуту ref компонента. Вот как это выглядит:
<input type="text" ref={element => this.textInput = element} />
Обратный вызов используется для хранения ссылки на узел DOM в свойстве экземпляра. Когда мы хотим использовать эту ссылку, мы получаем доступ к ней, используя:
this.textInput.value
Посмотрите, как это выглядит в том же примере, который мы использовали ранее.
Когда вы используете обратный вызов, как мы это делали выше, React выполнит обратный вызов ref с узлом DOM, когда компонент будет монтироваться; когда компонент будет размонтироваться, он будет назван с нулем. Также возможно передать ref из родительского компонента в дочерний, используя обратные вызовы.
Давайте создадим наш «немой» компонент, который выводит простые введенные данные:
const Input = props => { return ( <div> <input type="text" ref={props.inputRef} /> </div> ); };
Этот компонент ожидает реквизиты inputRef из своего родительского компонента, которые затем используются для создания ссылки на узел DOM. Вот родительский компонент:
class App extends React.Component { state = { value: '' }; handleSubmit = event => { this.setState({ value: this.inputElement.value }); }; render() { return ( <div> <h1>React Ref - Callback Ref</h1> <h3>Value: {this.state.value}</h3> <Input inputRef={el => (this.inputElement = el)} /> <button onClick={this.handleSubmit}>Submit</button> </div> ); } }
В компоненте App мы хотим получить текст, который вводится в поле ввода (которое находится в дочернем компоненте), чтобы мы могли его отобразить. Ссылка создается с помощью обратного вызова, как в первом примере этого раздела. Ключевым моментом является то, как мы получаем доступ к DOM элемента ввода в компоненте Input из компонента App. Если вы внимательно посмотрите код, мы обращаемся к нему с помощью this.inputElement. Таким образом, при обновлении состояния значения в компоненте App мы получаем текст, который был введен в поле ввода, используя this.inputElement.value.
Атрибут ref как строка
Это старый способ создания ссылки, и, скорее всего, он будет удален в будущей версии из-за некоторых связанных с ним проблем. Команда React советует не использовать его, поскольку он помечен в документации, как «устаревший». Мы все равно включаем его в эту статью, потому что есть шанс, что вы встретите его в базе кода.
Возвращаясь к нашему примеру элемента ввода, значение которого используется для обновления передаваемого текстового значения:
class App extends React.Component { state = { value: '' } handleSubmit = e => { e.preventDefault(); this.setState({ value: this.refs.textInput.value}) }; render() { return ( <div> <h1>React Ref - String Ref</h1> <h3>Value: {this.state.value}</h3> <form onSubmit={this.handleSubmit}> <input type="text" ref="textInput" /> <button>Submit</button> </form> </div> ); } }
Инициализируется компонент, и мы начинаем со значения по умолчанию — пустой строки (value = »). Компонент отображает текст и форму, как обычно, и, как и раньше, текст H3 обновляет состояние, когда форма отправляется с содержимым, введенным в поле ввода.
Мы создали ref, установив для свойства ref поля ввода — textInput. Это дает нам доступ к значению элемента ввода в методе handleSubmit(), используя this.refs.textInput.value.
Пересылка ref от одного компонента в другой
** Пересылка ref — это метод передачи ref от компонента к дочернему компоненту с использованием метода React.forwardRef ().
Вернемся к нашему примеру поля ввода, которое обновляет значение текста при его отправке:
class App extends React.Component { constructor(props) { super(props) this.inputRef = React.createRef(); this.state = { value: '' } } handleSubmit = e => { e.preventDefault(); this.setState({ value: this.inputRef.current.value}) }; render() { return ( <div> <h1>React Ref - createRef</h1> <h3>Value: {this.state.value}</h3> <form onSubmit={this.handleSubmit}> <Input ref={this.inputRef} /> <button>Submit</button> </form> </div> ); } }
В этом примере мы создали ref со значением inputRef, и хотим передать его дочернему компоненту в качестве атрибута ref, который мы можем использовать для обновления состояния текста.
const Input = React.forwardRef((props, ref) => ( <input type="text" ref={ref} /> ));
Вот альтернативный способ сделать это, указав ref вне компонента App:
const Input = React.forwardRef((props, ref) => ( <input type="text" ref={ref} /> )); const inputRef = React.createRef(); class App extends React.Component { constructor(props) { super(props) this.state = { value: '' } } handleSubmit = e => { e.preventDefault(); this.setState({ value: inputRef.current.value}) }; render() { return ( <div> <h1>React Ref - createRef</h1> <h3>Value: {this.state.value}</h3> <form onSubmit={this.handleSubmit}> <Input ref={inputRef} /> <button>Submit</button> </form> </div> ); } }
Использование ref для валидации формы
Мы все знаем, что валидация формы — это что-то очень сложное, но это то, с чем отлично справляется React. Вы прекрасно знаете о таких вещах, как проверка заполнения обязательных полей. Или проверка наличия в пароле, как минимум, шести символов. Refs может использоваться и в этих случаях.
class App extends React.Component { constructor(props) { super(props); this.username = React.createRef(); this.password = React.createRef(); this.state = { errors: [] }; } handleSubmit = (event) => { event.preventDefault(); const username = this.username.current.value; const password = this.password.current.value; const errors = this.handleValidation(username, password); if (errors.length > 0) { this.setState({ errors }); return; } // Submit data }; handleValidation = (username, password) => { const errors = []; // Require username to have a value on submit if (username.length === 0) { errors.push("Username cannot be empty"); } // Require at least six characters for the password if (password.length < 6) { errors.push("Password should be at least 6 characters long"); } // If those conditions are met, then return error messaging return errors; }; render() { const { errors } = this.state; return ( <div> <h1>React Ref Example</h1> <form onSubmit={this.handleSubmit}> // If requirements are not met, then display errors {errors.map(error => <p key={error}>{error}</p>)} <div> <label>Username:</label> // Input for username containing the ref <input type="text" ref={this.username} /> </div> <div> <label>Password:</label> // Input for password containing the ref <input type="text" ref={this.password} /> </div> <div> <button>Submit</button> </div> </form> </div> ); } }
Мы использовали createRef() для создания ref для поля ввода и передали его в качестве параметра методу валидации. Мы заполняем массив ошибок, когда в одном из полей ввода возникает ошибка, которую мы затем отображаем пользователю.
Вот и все о ref!
Надеюсь, это пошаговое руководство дало вам представление о том, насколько мощными может быть ref. Это отличный способ обновить часть компонента без необходимости повторной обработки. Это удобно для написания более компактного кода и повышения производительности.
В то же время стоит прислушаться к советам документации самого React и не использовать ref слишком часто:
«Первым признаком того, что вам стоит использовать ref, может быть ситуация, когда вам нужно «заставить, чтобы что-то случилось» в вашем приложении. В этом случае, подумайте на тем, какому компоненту в иерархии компонентов должно принадлежать состояние. Часто становится становится понятно, что это должен быть компонент более высокого уровня в иерархии».
Вам все понятно? Отлично.
Автор: Kingsley Silas
Источник: https://css-tricks.com/
Редакция: Команда webformyself.