Comments 24
Как альтернатива — можно использовать строковое название и тогда не придется каждый вызов создавать анонимную функцию, не знаю, почему в статье нету этого примера.
edit: таки описано:
не хватает аргументов, почему рекомендуют.
class Hello extends React.Component {
constructor() {
this.focus = this.focus.bind(this);
}
handleClick() {
this.refs.myTextInput.focus();
}
render() {
return (
<div>
<input type="text" ref="myTextInput" />
<input type="button" value="Focus" onClick={this.focus} />
</div>
);
}
}
edit: таки описано:
Использование обратного вызова ref для установки свойства в классе — это общепринятый шаблон для доступа к элементам DOM. Если в настоящий момент для этой задачи вы используете this.refs.myRefName, мы рекомендуем перейти к использованию описанного нами шаблона.
не хватает аргументов, почему рекомендуют.
В статье об этом написано:
Использование обратного вызова ref для установки свойства в классе — это общепринятый шаблон для доступа к элементам DOM. Если в настоящий момент для этой задачи вы используете this.refs.myRefName, мы рекомендуем перейти к использованию описанного нами шаблона.
Не надо давать уникальные имена универсальным шаблонным элементам, можно использовать универсальные функции. Представьте, что у вас 2 inputa и 2 кнопки. И там и там одинаковый функционал.
не хватает аргументов, почему рекомендуют.
У меня сложилось впечатление, что это для того, чтобы люди избегали использования ref как таковых, окромя тех ситуаций, когда иначе никак. Может быть с их точки зрения, люди злоупотребляют этой возможностью в ущерб react-way.
Тогда надо сделать depricated, а потом убрать )
Да, если добавить сюда ранее не документированный контекст, dangerouslySetInnerHTML={{ __html: «Hello» }}, вечные предупреждения при управлении div[contenteditable=«true»] — то получится сплошная политика запретов. VUE в этом плане куда свободнее
У меня сложилось впечатление, что это для того, чтобы люди избегали использования ref как таковых, окромя тех ситуаций, когда иначе никак.
И молодцы. Дали теперь возможность таким людям писать что-то вроде такого:
<input ref={(input) => calculateSomething()} />
Архитекторы очень мудры
Вопрос к эксперту: а разве такого рода даже анонимные функции не успешно ли оптимизируются движком и фактически функция заново не создается? Или все же она сразу же выбрасывается из памяти после выполнения render
?
Если только с точки зрения теории, то стоит не забывать, что это не просто блок кода, а объект первого класса, он создается, к нему цепляется scope и prototype, его присваивают переменной. Чистые функции легче оптимизировать (там нет необходимости оставлять замыкание), эта функция грязная.
На практике даже самые современные браузеры не всегда очищают память, если на неё была замкнута функция даже если эта функция уже неактуальна (это что-то вроде перекресных ссылок). И тем больше вероятность чем сложнее приложение, а одна неудачная неочищенная ссылка тянет за собой целый ворох мусора. А код реакта как раз крайне нетривиален.
Более того, кроме чисто js-нюансов есть и важная особенность Реакта. Процитирую из документации:
То есть каждую перерисовку LoggingButton внутренний button будет получать НОВЫЙ экземпляр функции и потому Реакт будет считать, что его необходимо обновить, хотя можно было бы использовать закешированный (старый) вариант, если бы экземпляр функции с контекстом был создан и сохранен изначально.
пс. Есть очень хорошая статья, которая поможет понять, что происходит и какая работа выполняется при создании анонимной функции: http://dmitrysoshnikov.com/ecmascript/ru-chapter-6-closures/
На практике даже самые современные браузеры не всегда очищают память, если на неё была замкнута функция даже если эта функция уже неактуальна (это что-то вроде перекресных ссылок). И тем больше вероятность чем сложнее приложение, а одна неудачная неочищенная ссылка тянет за собой целый ворох мусора. А код реакта как раз крайне нетривиален.
Более того, кроме чисто js-нюансов есть и важная особенность Реакта. Процитирую из документации:
class LoggingButton extends React.Component { handleClick() { console.log('this is:', this); } render() { // This syntax ensures `this` is bound within handleClick return ( <button onClick={(e) => this.handleClick(e)}> Click me </button> ); } }
The problem with this syntax is that a different callback is created each time the LoggingButton renders. In most cases, this is fine. However, if this callback is passed as a prop to lower components, those components might do an extra re-rendering. We generally recommend binding in the constructor or using the property initializer syntax, to avoid this sort of performance problem.
То есть каждую перерисовку LoggingButton внутренний button будет получать НОВЫЙ экземпляр функции и потому Реакт будет считать, что его необходимо обновить, хотя можно было бы использовать закешированный (старый) вариант, если бы экземпляр функции с контекстом был создан и сохранен изначально.
пс. Есть очень хорошая статья, которая поможет понять, что происходит и какая работа выполняется при создании анонимной функции: http://dmitrysoshnikov.com/ecmascript/ru-chapter-6-closures/
То есть каждую перерисовку LoggingButton внутренний button будет получать НОВЫЙ экземпляр функции и потому Реакт будет считать, что его необходимо обновить, хотя можно было бы использовать закешированный (старый) вариант, если бы экземпляр функции с контекстом был создан и сохранен изначально.
Следует понимать что это актуально только если реализовывается shouldComponentUpdate со сравнением функций переданных через props. Стандартная реализация shouldComponentUpdate просто возвращает true, поэтому компоненту глубоко плевать на то, новосозданная это функция или закешированная.
П.С. вот хорошая статья на тему производительности реакта http://blog.csssr.ru/2016/12/07/react-perfomance/
Вот тут участники реакта немного проясняют свою позицию:
There are multiple problems with it:
- It requires that React keeps track of currently rendering component (since it can't guess this). This makes React a bit slower.
- It doesn't work as most people would expect with the «render callback» pattern (e.g.
) because the ref would get placed on DataGrid for the above reason.<DataGrid renderRow={this.renderRow} />
- It is not composable, i.e. if a library puts a ref on the passed child, the user can't put another ref on it (e.g. #8734). Callback refs are perfectly composable.
Опять невалидное. Почему бы им просто не использовать data-атрибуты. Каждый пытается свою спецификацию сделать…
Дык, эти атрибуты же не добираются до DOM. Это внутренняя кухня.
Если честно просто не пользуюсь реактом(и ангуляром из-за несоблюдения стандартов), но в любом случае этих атрибутом нет в спецификации. Есть data-атрибуты. Вы хотите сказать, что в выхлопе на HTML они урезаются чтоли или переформируются в валидный код?
В Реакте не используется HTML, JSX (JS+XML) не надмножество ни HTML, ни даже xHTML. Как говорится, все элементы и атрибуты XML вымышлены, все совпадения с HTML случайны. JSX-элементы «рендерятся» в вызовы JS-функций CreateElement, которые возвращают элементы виртуального DOM, которые потом «рендерятся» в реальный. HTML в процессе вообще не участвует (серверный рендеринг опустим для простоты), а алгоритм маппинга виртуального DOM на реальный может быть произвольным. Стараются, конечно быть поближе к HTML, но священную корову из него не делают, не просто расширяя или урезая его, но и меняя синтаксис.
В общем и в целом, часть атрибутов передаётся as is, часть переформатируется в валидный код, часть урезается.
В общем и в целом, часть атрибутов передаётся as is, часть переформатируется в валидный код, часть урезается.
Кому надоел React, ставьте плюс. :)
Кому нравиться, пройдите мимо. :)
Кому нравиться, пройдите мимо. :)
Sign up to leave a comment.
Ref-атрибуты и DOM в React