Разница между рендерингом и опорой компонента в React Router v4
Так что недавно я читаю документацию React-Router и сильно не понимаю, что такое рендеринг компонента Route и свойство component, документ скажем, для компонента prop:
Когда вы используете
component
(вместоrender
илиchildren
, ниже) маршрутизатор используетReact.createElement
для создания нового элемента React из данного компонента. Это означает, что если вы предоставите встроенную функцию дляcomponent
prop, вы будете создавать новый компонент при каждой визуализации. Это приводит к размонтированию существующего компонента и монтированию нового компонента вместо простого обновления существующего компонента. При использовании встроенной функции для встроенного рендеринга используйте опоруrender
илиchildren
(ниже).
Довольно запутанно, не правда ли? Но я наконец понял это.
Ключом к пониманию этого является утверждение «предоставить встроенную функцию для свойства компонента».
Все мы знаем, что компонент Route будет повторно визуализироваться при изменении местоположения, и React будет сравнивать старое и новое виртуальное дерево DOM, получить некоторый результат сравнения и применить его к реальной DOM.
И react будет стараться изо всех сил повторно использовать узел DOM, если только свойство type или key нового ReactElement не будет изменено.
So
// 1. const componentA = React.createElement(AppComponent, props) const componentB = React.createElement(AppComponent, props) console.log(componentA.type === componentB.type) // true
// 2. const componentA = React.createElement(() => <AppComponent />, props) const componentB = React.createElement(() => <AppComponent />, props) console.log(componentA.type === componentB.type) // false
Все ReactElements, созданные способом 1, имеют один и тот же тип (AppComponent), но они не имеют одного и того же типа, если все они созданы способом 2.
Почему?
Поскольку всегда существует новая анонимная функция, созданная способом 2, когда вызывается метод рендеринга родительского компонента (компонент, содержащий компонент Route), поэтому тип нового и старого ReactElement - это два разных экземпляра анонимная функция
() => <AppComponent />
Таким образом, с точки зрения React, существуют разные типы элементов, и при повторном рендеринге их следует обрабатывать операцией размонтировать старый ›монтировать новый, то есть каждое состояние или изменения, внесенные вами в старый компонент. теряется каждый раз при повторном рендеринге родительского компонента.
Но почему свойство render может избежать размонтирования и монтирования? Это тоже анонимная функция !?
Здесь я хотел бы сослаться на исходный код метода рендеринга компонента Route:
if (component) // We already know the differences for these two: // React.createElement(AppComponent) // React.createElement(() => <AppComponent />) return match ? React.createElement(component, props) : null
if (render) return match ? render(props) : null
render prop - это функция, которая при вызове возвращает ReactElement, теперь останавливается и тратит несколько секунд на размышления - какой тип возвращаемого элемента?
<Route render={() => <AppComponent />}></Route>
Это AppComponent, а не оболочка анонимной функции! Потому что после компиляции jsx мы получили:
if render = () => React.createElement(AppComponent)
then render() = React.createElement(AppComponent)
ifReact.createElement(render) = React.createElement(() => React.createElement(AppComponent))
then React.createElement(render()) = React.createElement(React.createElement(AppComponent))
Поэтому, когда вы используете рендеринг вместо свойства компонента, тип элемента, который возвращает функция рендеринга, не будет изменяться при каждом рендеринге, даже если всегда создается новый экземпляр анонимной функции, созданный на каждый вызов parentElement.render ().
С моей точки зрения, вы можете добиться того же поведения, что и render prop с компонентом prop, задав имя анонимной функции и поместив ее вне родительского метода render:
// Put this line outside render method. const CreateAppComponent = () => <AppComponent />
// Inside render method render(){ return <Route component={CreateAppComponent}/> }
Таким образом, можно сделать вывод, что производительность не различается между компонентом и опорой рендеринга, если вы используете component={AppComponent}
напрямую, если вы хотите назначить некоторые реквизиты для AppComponent, используйте render={() => <AppComponent {...props}/> }
вместо component={() => <AppComponent {...props}/> }