Разница между рендерингом и опорой компонента в React Router v4

Так что недавно я читаю документацию React-Router и сильно не понимаю, что такое рендеринг компонента Route и свойство component, документ скажем, для компонента prop:

Когда вы используете component (вместо render или children, ниже) маршрутизатор использует React.createElement для создания нового элемента React из данного компонента. Это означает, что если вы предоставите встроенную функцию для componentprop, вы будете создавать новый компонент при каждой визуализации. Это приводит к размонтированию существующего компонента и монтированию нового компонента вместо простого обновления существующего компонента. При использовании встроенной функции для встроенного рендеринга используйте опору 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)
if
  React.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}/> }