Почему компоненты ReactJS должны вести себя как чистые функции?

в документации говорится, что все компоненты React должны вести себя как чистые функции по отношению к своим реквизитам. https://facebook.github.io/react/docs/components-and-props.html, но не объясняет настоящую причину этого, почему так?


person nomadus    schedule 01.02.2017    source источник


Ответы (4)


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

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

Удивительно определять пользовательский интерфейс на основе состояния и перерисовывать пользовательский интерфейс каждый раз, когда изменяется какая-либо часть состояния. Но вы можете себе представить, что выполнение полного повторного рендеринга всего DOM каждый раз, когда вы что-то меняете, было бы мучительно медленным. React решает эту проблему, проверяя минимальное количество изменений, необходимых в DOM для отражения нового состояния. Он знает, что эти изменения основаны на том, какие свойства и состояние получает каждый компонент, и может сказать, нужно ли обновлять компонент, если какое-либо из его свойств или состояния изменилось.

Возьмите это дерево в качестве примера иерархии компонентов.

Дерево состояний

Здесь мы изменили h на 8, поэтому мы также изменили f, потому что h является потомком f, и мы также изменили c, потому что f является потомком c и так далее.

Ключевым моментом здесь является то, как React проверяет дерево компонентов. Плохо начать с корня и увидеть, как он изменился. Затем он проверит всех дочерних элементов и обнаружит, что изменились только c, поэтому нет необходимости проверять все ветки a и b. Затем он проверит ветвь c и обнаружит, что изменена только f, поэтому нет необходимости проверять e и g. Эта операция выполняется для каждого компонента, чтобы рассчитать минимальное количество изменений, а также то, что необходимо обновить.

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

person Marco Scabbiolo    schedule 01.02.2017
comment
Привет Марко, спасибо за ответ. Я вижу, что если реквизиты не меняются, это приводит к более эффективному алгоритму сравнения, но, с другой стороны, React имеет дело с состоянием, которое изменяется. То есть с пропсами мы получаем лучшую производительность, а с состоянием — нет? - person nomadus; 02.02.2017
comment
И состояние, и реквизиты учитываются в алгоритме сравнения, поэтому производительность в этом отношении должна быть одинаковой. Я думаю, что обсуждение состояния и реквизита больше связано с соглашениями и архитектурными шаблонами, чем с производительностью. - person Marco Scabbiolo; 02.02.2017

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

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

person Diego Faria    schedule 01.02.2017

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

Допустим, у вас есть два компонента, компонент A и компонент B, и компонент A является родительским для компонента B. Компонент A имеет свое собственное состояние, основанное на каких-то данных. Когда вы передаете часть своего состояния в качестве реквизита компоненту B, вы устанавливаете контракт между двумя компонентами, который компонент B делегирует компоненту A, чтобы получить значение указанного реквизита.

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

Вот что объясняется в официальной документации по реакции

https://facebook.github.io/react/blog/2015/02/24/streamlining-react-elements.html#problem-mutating-props-you-dont-own

person finalfreq    schedule 01.02.2017

Вы узнаете «почему», понимая алгоритм согласования, который React использует для рендеринга.

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

Частично это хорошо объяснено в ответе Марко Скаббиоло, но если вы хотите понять, как работает React, я настоятельно рекомендую вам прочитать пост, который я предложил.

Размещать ответ здесь было бы слишком много для поста и не нужно, потому что он уже объяснен командой React. Вот почему я предпочитаю давать вам источник напрямую.

person Facundo La Rocca    schedule 01.02.2017