React16 общий анализ API и принципиальный анализ
содержание
-
Vue
а такжеReact
Грубое сравнение двух фреймворков -
react 16
обычная версияapi
-
react
Жизненный цикл -
react
механизм события -
react.Component
Как реализовать компонентность и применение компонентов высшего порядка -
setState
Асинхронное управление данными очереди -
react Fiber
Анализ архитектуры react hooks
-
dom
изdiff
алгоритм -
snabbdom
Как упростить исходный кодVirtual DOM
из -
redux
Как спроектировать архитектуру одностороннего потока данных
Vue
а такжеReact
Грубое сравнение двух фреймворков
Преимущества Vue включают в себя:
- Гибкий выбор шаблонов и функций рендеринга
- Простой синтаксис и создание проекта
- Более быстрый рендеринг и меньший размер
К сильным сторонам React относятся:
- Лучше для больших приложений и лучшей тестируемости
- Работает как с веб-приложениями, так и с нативными
- Больше поддержки и инструментов из более крупной экосистемы
сходство
React и Vue имеют много общего, React и Vue — отличные фреймворки, у них больше сходства, чем различий, и большинство их лучших функций являются общими: оба они представляют собой фреймворк пользовательского интерфейса JavaScript, ориентированный на создание многофункциональных интерфейсных приложений. В отличие от «полнофункциональных» ранних фреймворков JavaScript, Reat и Vue имеют только скелет фреймворка, а другие функции, такие как маршрутизация, управление состоянием и т. д., являются отдельными компонентами фреймворка.
- Обе являются библиотеками JavaScript для создания пользовательского интерфейса;
- Оба быстрые и легкие;
- Оба имеют компонентную архитектуру;
- Все используют виртуальный DOM;
- Все они могут быть помещены в один файл HTML или стать модулями в более сложных настройках веб-пакета;
- Существуют независимые, но широко используемые библиотеки управления маршрутизаторами и состояниями;
- Самая большая разница между ними заключается в том, что Vue обычно использует файлы шаблонов HTML, а React — полностью JavaScript. Vue имеет синтаксический сахар двустороннего связывания.
разница
- Компоненты Vue делятся на глобальную регистрацию и локальную регистрацию.В реакции соответствующие компоненты импортируются, а затем ссылаются на них в шаблоне;
- Пропсы могут динамически изменяться, а подкомпоненты обновляться в реальном времени.В React официально рекомендуется, чтобы пропсы были как чистые функции, с согласованным вводом и выводом, и не рекомендуется менять представления через пропсы;
- Дочерний компонент обычно вызывает опцию props явно, чтобы объявить данные, которые он ожидает получить. В реакции нет необходимости, в двух других есть механизм проверки реквизита;
- Каждый экземпляр Vue реализует интерфейс событий для облегчения связи между родительскими и дочерними компонентами.В небольших проектах нет необходимости внедрять механизм управления состоянием, и react должен реализовать его сам;
- Распространяйте содержимое с помощью слотов, что позволяет смешивать содержимое родительского компонента с собственным шаблоном дочернего компонента;
- Существует больше систем инструкций, так что шаблон может выполнять более богатые функции, в то время как React может использовать только синтаксис JSX;
- Vue добавляет вычисляемые и наблюдаемые синтаксические сахара, но в React для этого нужно написать набор логики;
- Идея реакции вся в js, html генерируется через js, поэтому jsx проектируется, а js используется для работы css, styled-component, jss сообщества и т. д., а vue — это объединение html, css , js вместе, используйте Для соответствующих методов обработки Vue имеет однофайловый компонент, который может записывать html, css и js в один файл, а html предоставляет механизм шаблонов для его обработки.
- React делает очень мало вещей, и многие из них оставлены сообществу.Многие вещи в Vue встроены, что действительно удобно писать.Например, combReducer из redux соответствует модулям vuex, а reselect соответствует геттер и vue компоненты vuex.Вычисляемая мутация vuex — это исходные данные, которые изменяются напрямую, а редуктор редукса должен возвращать новое состояние, поэтому редукс объединяет неизменяемые для оптимизации производительности, а vue в этом не нуждается.
- Общая идея реакции функциональна, поэтому она уважает чистые компоненты, данные неизменяемы и односторонний поток данных.Конечно, это можно сделать и в двусторонних местах.Например, в сочетании с редукционной формой , горизонтальное разделение компонентов обычно выполняется через компоненты высокого порядка. А vue — это изменяемые данные, двусторонняя привязка, декларативное написание, а миксин во многих случаях используется для горизонтального разделения компонентов vue.
общественная деятельность
Из производительности двоих на github (данные взяты от 16 сентября 2019 г.)
Видно, что количество звездочек у Vue уже самое популярное во фронтенд-фреймворке. С точки зрения обслуживания, реакция поддерживается Facebook, и хотя на данном этапе у vue есть команда, в основном именно Ю Юйси поддерживает и вносит свой код, а гибридная платформа с открытым исходным кодом Weex от Alibaba также основана на vue, поэтому мы верим, что в будущем vue будет поддерживаться большим количеством людей и команд.
По неполной статистике, в том числе Ele.me, Jianshu, AutoNavi, Rare Earth Nuggets, Suning.com, Meituan, Tmall, Lizhi FM, Fangduoduo, Laravel, htmlBurger и другие известные отечественные и зарубежные компании используют vue для разработки новых проекты и фронтенд-рефакторинг старых проектов.
Компании, использующие React facebook, Twitter, INS, Airbnb, Yahoo, ThoughtWorks, Ant Financial, Alibaba, Tencent, Baidu, Koubei, Meituan, Didi Chuxing, Ele.me, JD.com, NetEase и т. д.
экология пользовательского интерфейса
vue | react | |
---|---|---|
ПК сторона | iview, элемент и т. д. | Ant Design, Material-UI и т. д. |
терминал h5 | Как вант, минтуй и т.д. | Муравей Дизайн Мобильный, Weui |
Гибридная разработка | weexui, буй-weex | teaset, реагировать на родные элементы |
Апплет WeChat | iview, Weapp, zanui | iView Weapp, пользовательский интерфейс Таро |
Независимо от того, выберете ли вы React.js или Vue.js, между этими двумя фреймворками нет существенной разницы, решение очень субъективно в зависимости от ваших требований. Vue.js — лучший выбор, если вы хотите интегрировать интерфейсную среду JavaScript в существующее приложение, и React определенно ваш выбор, если вы хотите создать мобильное приложение с помощью JavaScript.
react16
обычная версияapi
Давайте посмотрим на API, выставленный реагированием
const React = {
Children: {
map,
forEach,
count,
toArray,
only
},
createRef,
Component,
PureComponent,
createContext,
forwardRef,
Fragment: REACT_FRAGMENT_TYPE,
StrictMode: REACT_STRICT_MODE_TYPE,
unstable_AsyncMode: REACT_ASYNC_MODE_TYPE,
unstable_Profiler: REACT_PROFILER_TYPE,
createElement: __DEV__ ? createElementWithValidation : createElement,
cloneElement: __DEV__ ? cloneElementWithValidation : cloneElement,
createFactory: __DEV__ ? createFactoryWithValidation : createFactory,
isValidElement: isValidElement,
version: ReactVersion,
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: ReactSharedInternals
}
Children
Этот объект предоставляет набор методов, которые помогут вам работать с props.children, поскольку children — это структура данных, подобная массиву, но не массив, и если вы хотите иметь с ним дело, вы можете использовать методы подключаемого модуля React.Children.
createRef
Новое использование ref, от которого React собирается отказаться<div ref="myDiv" />
Это использование строки ref, вы можете использовать ref только двумя способами в будущем.
class App extends React.Component {
constructor() {
this.ref = React.createRef()
}
render() {
return <div ref={this.ref} />
// or
return <div ref={node => (this.funRef = node)} />
}
}
createContext
createContext
Это официально доработанное контекстное решение. Старые контекстные API, которые мы использовали ранее, - это API, которые React не рекомендует. Теперь новые API выпущены, и официальный представитель подтвердил, что старые API будут удалены в 17-й версии ( старые API). производительность в целом неплохая).
Как использовать новый API:
const { Provider, Consumer } = React.createContext('defaultValue')
const ProviderComp = (props) => (
<Provider value={'realValue'}>
{props.children}
</Provider>
)
const ConsumerComp = () => (
<Consumer>
{(value) => <p>{value}</p>}
</Consumber>
)
жизненный цикл реакции
В настоящее время жизненный цикл React 16.8+ разделен на три этапа: этап монтирования, этап обновления и этап выгрузки.
- Стадия монтирования:
constructor(props)
: создать экземпляр.
static getDerivedStateFromProps
отprops
получено вstate
.
render
оказывать.
componentDidMount
: Завершите монтаж.
- Этап обновления:
static getDerivedStateFromProps
Получить состояние из реквизита.
shouldComponentUpdate
Определите, требуется ли перекраска.
render
оказывать.
getSnapshotBeforeUpdate
Получите снимок.
componentDidUpdate
Обратный вызов после завершения рендеринга. - Этап удаления:
componentWillUnmount
Насчет удаления. - Обработка ошибок:
static getDerivedStateFromError
получить от ошибкиstate
.
componentDidCatch
Найдите ошибку и обработайте ее.
class ExampleComponent extends react.Component {
// 构造函数,最先被执行,我们通常在构造函数里初始化state对象或者给自定义方法绑定this
constructor() {}
//getDerivedStateFromProps(nextProps, prevState)用于替换 `componentWillReceiveProps` ,该函数会在初始化和 `update` 时被调用
// 这是个静态方法,当我们接收到新的属性想去修改我们state,可以使用getDerivedStateFromProps
static getDerivedStateFromProps(nextProps, prevState) {
// 新的钩子 getDerivedStateFromProps() 更加纯粹, 它做的事情是将新传进来的属性和当前的状态值进行对比, 若不一致则更新当前的状态。
if (nextProps.riderId !== prevState.riderId) {
return {
riderId: nextProps.riderId
}
}
// 返回 null 则表示 state 不用作更新
return null
}
// shouldComponentUpdate(nextProps, nextState),有两个参数nextProps和nextState,表示新的属性和变化之后的state,返回一个布尔值,true表示会触发重新渲染,false表示不会触发重新渲染,默认返回true,我们通常利用此生命周期来优化react程序性能
shouldComponentUpdate(nextProps, nextState) {
return nextProps.id !== this.props.id
}
// 组件挂载后调用
// 可以在该函数中进行请求或者订阅
componentDidMount() {}
// getSnapshotBeforeUpdate(prevProps, prevState):这个方法在render之后,componentDidUpdate之前调用,有两个参数prevProps和prevState,表示之前的属性和之前的state,这个函数有一个返回值,会作为第三个参数传给componentDidUpdate,如果你不想要返回值,可以返回null,此生命周期必须与componentDidUpdate搭配使用
getSnapshotBeforeUpdate() {}
// 组件即将销毁
// 可以在此处移除订阅,定时器等等
componentWillUnmount() {}
// 组件销毁后调用
componentDidUnMount() {}
// componentDidUpdate(prevProps, prevState, snapshot):该方法在getSnapshotBeforeUpdate方法之后被调用,有三个参数prevProps,prevState,snapshot,表示之前的props,之前的state,和snapshot。第三个参数是getSnapshotBeforeUpdate返回的,如果触发某些回调函数时需要用到 DOM 元素的状态,则将对比或计算的过程迁移至 getSnapshotBeforeUpdate,然后在 componentDidUpdate 中统一触发回调或更新状态。
componentDidUpdate() {}
// 渲染组件函数
render() {}
// 以下函数不建议使用
UNSAFE_componentWillMount() {}
UNSAFE_componentWillUpdate(nextProps, nextState) {}
UNSAFE_componentWillReceiveProps(nextProps) {}
}
В React версии 17 будут объявлены устаревшие несколько жизненных циклов API компонентов класса:componentWillMount
,componentWillReceiveProps
а такжеcomponentWillUpdate
.
механизм событий реакции
Просто поймите, как React обрабатывает события.React регистрирует события для документирования через addEventListener, когда компоненты загружаются (монтируются) и обновляются (обновляются), а затем будет пул событий, в котором хранятся все события, когда события запускаются, через dispatchEvent для распределения событий. .ЦитироватьНепонятные моменты для начинающих, чтобы научиться реагировать (2)
- Способ привязки событий в реакции похож на привязку событий в HTML, использование верблюжьего регистра для указания связываемого свойства onClick — это метод, определенный компонентом {this.handleClick.bind(this)}.
- Поскольку метод класса не привязывает this по умолчанию, если вы забудете привязать его при вызове, значение this будет неопределенным. Обычно, если он не вызывается напрямую, он должен быть привязан к методу, а контекст функции события должен быть привязан к экземпляру компонента.
Четыре способа привязки событий
class Button extends react.Component {
constructor(props) {
super(props)
this.handleClick1 = this.handleClick1.bind(this)
}
//方式1:在构造函数中使用bind绑定this,官方推荐的绑定方式,也是性能最好的方式
handleClick1() {
console.log('this is:', this)
}
//方式2:在调用的时候使用bind绑定this
handleClick2() {
console.log('this is:', this)
}
//方式3:在调用的时候使用箭头函数绑定this
// 方式2和方式3会有性能影响并且当方法作为属性传递给子组件的时候会引起重渲问题
handleClick3() {
console.log('this is:', this)
}
//方式4:使用属性初始化器语法绑定this,需要babel转义
handleClick4 = () => {
console.log('this is:', this)
}
render() {
return (
<div>
<button onClick={this.handleClick1}>Click me</button>
<button onClick={this.handleClick2.bind(this)}>Click me</button>
<button onClick={() => this.handleClick3}>Click me</button>
<button onClick={this.handleClick4}>Click me</button>
</div>
)
}
}
Почему я получаю ошибку при прямом вызове метода
class Foo extends React.Component {
handleClick() {
this.setState({ xxx: aaa })
}
render() {
return <button onClick={this.handleClick.bind(this)}>Click me</button>
}
}
будет преобразован Babel в
React.createElement(
'button',
{
onClick: this.handleClick
},
'Click me'
)
«Синтетические события» и «Нативные события»
react реализует слой "синтетических событий" (synthetic event system
), что устранило проблемы совместимости событий в разных браузерах. Все события регистрируются на самом верхнем элементе — документе, а «синтетические события» делегируются событиями (event delegation
) привязан к верхнему слою компонента, а когда компонент выгружен (unmount
) автоматически уничтожает связанное событие.
разработка реактивного компонента
Идея компонентизации React
Полный шаблон для компонента пользовательского интерфейса
import classNames from 'classnames'
class Button extends react.Component {
//参数传参与校验
static propTypes = {
type: PropTypes.oneOf(['success', 'normal']),
onClick: PropTypes.func
}
static defaultProps = {
type: 'normal'
}
handleClick() {}
render() {
let { className, type, children, ...other } = this.props
const classes = classNames(
className,
'prefix-button',
'prefix-button-' + type
)
return (
<span className={classes} {...other} onClick={() => this.handleClick}>
{children}
</span>
)
}
}
Функциональный компонент
Чистый тип дисплея, не нужно поддерживать состояние и жизненный цикл, предпочтительно использоватьFunction Component
- Код стал более лаконичным, сразу видно, что это чисто дисплейный тип, без сложной бизнес-логики
- Лучшая возможность повторного использования. Пока реквизиты одной и той же структуры передаются, один и тот же интерфейс может отображаться без учета побочных эффектов.
- Небольшой размер упаковки и высокая эффективность исполнения
import react from 'react'
function MyComponent(props) {
let { firstName, lastName } = props
return (
<div>
<img src="avatar.png" className="profile" />
<h3>{[firstName, lastName].join(' ')}</h3>
</div>
)
}
будет сбежит вавилон как
return React.createElement(
'div',
null,
React.createElement('img', { src: 'avatar.png', className: 'profile' }),
React.createElement('h3', null, [firstName, lastName].join(' '))
)
Так,React.createElement
Что ты делаешь? Взгляните на соответствующую часть кода:
var ReactElement = function(type, key, ref, self, source, owner, props) {
var element = {
// This tag allow us to uniquely identify this as a React Element
?typeof: REACT_ELEMENT_TYPE,
// Built-in properties that belong on the element
type: type,
key: key,
ref: ref,
props: props,
// Record the component responsible for creating this element.
_owner: owner
}
// ...
return element
}
ReactElement.createElement = function(type, config, children) {
// ...
return ReactElement(
type,
key,
ref,
self,
source,
ReactCurrentOwner.current,
props
)
}
React.createElement() для создания элементов React. Он принимает три параметра, первый тип параметра может быть именем метки. Например, div, span или компонент React. Второй параметр props — это входящее свойство. Третий и последующие параметры потомки используются как дочерние компоненты компонента.
createElement
Функция обрабатывает специальные реквизиты, такие как ключ и ссылка, и получаетdefaultProps
Назначьте значения свойствам по умолчанию, обработайте входящие дочерние узлы и, наконец, создайтеreactElement
объекты (так называемый виртуальный DOM).reactDOM.render
Визуализировать сгенерированный виртуальный DOM в указанный контейнер, который использует пакетную обработку, транзакции и другие механизмы, выполняет оптимизацию производительности для определенных браузеров и, наконец, преобразует его в настоящий DOM.
ES6 class
Определите чистый компонент (PureComponent
)
Предпочтение отдается компонентам, которым необходимо поддерживать состояние или использовать методы жизненного цикла.PureComponent
class MyComponent extends react.Component {
render() {
let { name } = this.props
return <h1>Hello, {name}</h1>
}
}
PureComponent
Component
& PureComponent
Эти два класса в основном одинаковы, единственная разницаPureComponent
На прототипе есть дополнительный логотип,shallowEqual
(поверхностное сравнение), чтобы решить, следует ли обновлять компонент, поверхностное сравнение похоже на поверхностное копирование, сравнивается только первый слой. использоватьPureComponent
Это равносильно пропуску записиshouldComponentUpdate
функция
if (ctor.prototype && ctor.prototype.isPureReactComponent) {
return !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
}
Это суждение, чтобы проверить, нужно ли обновлять компонент.ctor - это наследование, которое вы объявили.Component
or PureComponent
class, он определит, наследуете ли вы отPureComponent,如果是的话就
shallowEqual
Сравните состояние и свойства.
Сравните один в ReactClassComponent
Нужно ли его обновлять, там всего два места. Сначала посмотрите, есть лиshouldComponentUpdate
метод, второй здесьPureComponent
судить
Используйте неизменяемые структуры данныхImmutablejs
Immutable.js
Это библиотека постоянных структур данных, разработанная Facebook в 2014 году. Постоянство означает, что после создания данных их нельзя изменить. Любая операция модификации, добавления или удаления вернет новуюImmutable
объект. Это может облегчить нам решение таких проблем, как кэширование, откат, обнаружение изменения данных и т. д., и упростить разработку. И предоставляет большое количество методов, похожих на нативный JS, иLazy Operation
функции, полнофункциональное программирование.
import { Map } from 'immutable'
const map1 = Map({ a: { aa: 1 }, b: 2, c: 3 })
const map2 = map1.set('b', 50)
map1 !== map2 // true
map1.get('b') // 2
map2.get('b') // 50
map1.get('a') === map2.get('a') // true
Видно, что модификация свойств map1 возвращает map2, они не указывают на одно и то же место хранения, декларирует только map1, и все операции его не изменят.
ImmutableJS
Предоставляет большое количество методов для обновления, удаления и добавления данных, что значительно облегчает нам работу с данными. Кроме того, родные типы иImmutableJS
Методы определения типа и преобразования:
import { fromJS, isImmutable } from 'immutable'
const obj = fromJS({
a: 'test',
b: [1, 2, 4]
}) // 支持混合类型
isImmutable(obj) // true
obj.size() // 2
const obj1 = obj.toJS() // 转换成原生 `js` 类型
ImmutableJS
Две самые большие особенности:immutable data structures
(постоянная структура данных) сstructural sharing
(Совместное использование структуры), постоянная структура данных гарантирует, что данные не могут быть изменены после создания.При использовании старых данных для создания новых данных старые данные не изменятся, и работа с новыми данными не повлияет на старые данные, такие как собственный js. Структурное совместное использование означает, что данные, которые не изменились, имеют общую ссылку, что не только снижает потребление производительности при глубоком копировании, но и уменьшает объем памяти.
Слева — старое значение, справа — новое значение, мне нужно изменить значение красного узла слева, сгенерированное новое значение изменяет все узлы между красным узлом и корневым узлом, то есть значение из всех голубых узлов старое значение ничего не меняет, другие места, где оно используется, не будут затронуты, и более половины синих узлов по-прежнему используются совместно со старым значением. существуетImmutableJS
Внутри создается специальная структура данных, объединяющая нативные значения с рядом частных свойств для созданияImmutableJS
Тип, каждый раз, когда значение изменяется, он сначала проходит вспомогательное обнаружение частного свойства, затем изменяет соответствующее частное свойство и реальное значение, которое необходимо изменить, и, наконец, генерирует новое значение. средний, поэтому производительность будет очень высокой.
Компоненты высшего порядка (higher order component
)
Компонент более высокого порядка — это функция, которая принимает компонент и возвращает новый компонент. HOC позволяет повторно использовать код, логику и абстракции начальной загрузки.
function visible(WrappedComponent) {
return class extends Component {
render() {
const { visible, ...props } = this.props
if (visible === false) return null
return <WrappedComponent {...props} />
}
}
}
Вышеприведенный код представляет собой простое приложение HOC.Функция получает компонент в качестве параметра и возвращает новый компонент.Новый компонент может получать видимые реквизиты и решать, отображать ли видимый в соответствии со значением visible. Наиболее распространенной является функция подключения Redux. Помимо простого совместного использования библиотек и простой композиции, лучший способ сделать HOC — разделить поведение между реагирующими компонентами. Если вы обнаружите, что пишете много кода в разных местах, чтобы делать одно и то же, вам следует подумать о рефакторинге кода в многоразовый HOC. Вот упрощенная реализация подключения:
export const connect = (
mapStateToProps,
mapDispatchToProps
) => WrappedComponent => {
class Connect extends Component {
static contextTypes = {
store: PropTypes.object
}
constructor() {
super()
this.state = {
allProps: {}
}
}
componentWillMount() {
const { store } = this.context
this._updateProps()
store.subscribe(() => this._updateProps())
}
_updateProps() {
const { store } = this.context
let stateProps = mapStateToProps
? mapStateToProps(store.getState(), this.props)
: {}
let dispatchProps = mapDispatchToProps
? mapDispatchToProps(store.dispatch, this.props)
: {}
this.setState({
allProps: {
...stateProps,
...dispatchProps,
...this.props
}
})
}
render() {
return <WrappedComponent {...this.state.allProps} />
}
}
return Connect
}
Код очень понятен, функция подключения на самом деле делает одну вещь.mapStateToProps
а такжеmapDispatchToProps
Они деконструируются и передаются в исходный компонент, чтобы мы могли использовать их непосредственно в исходном компоненте.props
Получатьstate
так же какdispatch
функция.
Применение компонентов более высокого порядка
Некоторым страницам необходимо записывать поведение пользователей, показатели производительности и т. д. Выполнение этих действий с помощью компонентов более высокого порядка может сэкономить много повторяющегося кода.
управление журналом
function logHoc(WrappedComponent) {
return class extends Component {
componentWillMount() {
this.start = Date.now()
}
componentDidMount() {
this.end = Date.now()
console.log(
`${WrappedComponent.dispalyName} 渲染时间:${this.end - this.start} ms`
)
console.log(`${user}进入${WrappedComponent.dispalyName}`)
}
componentWillUnmount() {
console.log(`${user}退出${WrappedComponent.dispalyName}`)
}
render() {
return <WrappedComponent {...this.props} />
}
}
}
в наличии, контроль доступа
function auth(WrappedComponent) {
return class extends Component {
render() {
const { visible, auth, display = null, ...props } = this.props
if (visible === false || (auth && authList.indexOf(auth) === -1)) {
return display
}
return <WrappedComponent {...props} />
}
}
}
проверка формы
Основываясь на приведенном выше примере с двусторонней привязкой, давайте возьмем еще один валидатор формы. Валидатор формы может содержать функции проверки и подсказки. При сбое проверки отображается сообщение об ошибке:
function validateHoc(WrappedComponent) {
return class extends Component {
constructor(props) {
super(props)
this.state = { error: '' }
}
onChange = event => {
const { validator } = this.props
if (validator && typeof validator.func === 'function') {
if (!validator.func(event.target.value)) {
this.setState({ error: validator.msg })
} else {
this.setState({ error: '' })
}
}
}
render() {
return (
<div>
<WrappedComponent onChange={this.onChange} {...this.props} />
<div>{this.state.error || ''}</div>
</div>
)
}
}
}
const validatorName = {
func: (val) => val && !isNaN(val),
msg: '请输入数字'
}
const validatorPwd = {
func: (val) => val && val.length > 6,
msg: '密码必须大于6位'
}
<HOCInput validator={validatorName} v_model="name"></HOCInput>
<HOCInput validator={validatorPwd} v_model="pwd"></HOCInput>
Недостатки HOC
- HOC необходимо обернуть или вложить в исходный компонент.Если HOC используется в больших количествах, это приведет к большому количеству вложений, что очень затруднит отладку.
- HOC могут захватывать реквизит и вызывать конфликты, если контракт не соблюдается.
render props
Простая техника для совместного использования кода между компонентами React с использованием реквизита, значением которого является функция. Компонент с параметром рендеринга принимает функцию, которая возвращает элемент React, и вызывает его вместо реализации собственной логики рендеринга.
<DataProvider render={data => <h1>Hello {data.target}</h1>} />
setState
управление данными
**НЕ ОБНОВЛЯЙТЕ СТАТУС НАПРЯМУЮ**// Wrong 此代码不会重新渲染组件,构造函数是唯一能够初始化 this.state 的地方。
this.state.comment = 'Hello'
// Correct 应当使用 setState():
this.setState({ comment: 'Hello' })
В жизненном цикле компонента или привязке события реакции setState обновляется асинхронно, и вызов setState в отложенном обратном вызове или обратном вызове привязки собственного события не обязательно является асинхронным.- Несколько вызовов setState() объединяются в один вызов для повышения производительности.
- this.props и this.state могут обновляться асинхронно и не должны полагаться на их значения для расчета следующего состояния.
// Wrong
this.setState({
counter: this.state.counter + this.props.increment
})
// Correct
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}))
Собственная привязка событий не будет обрабатываться синтетическими событиями, но войдет в поток обработки транзакций обновления. То же самое верно и для `setTimeout`. Когда обратный вызов `setTimeout` выполняется, исходный процесс обновления компонента завершен, и он не будет помещен в `dirtyComponent` для асинхронного обновления, и результат, естественно, будет синхронным.
setState
принцип
setState не выполняет рендеринг напрямую, а выполняетupdateQueue
(очередь асинхронного обновления),
setState( stateChange ) {
Object.assign( this.state, stateChange );
//合并接收到的state||stateChange改变的state(setState接收到的参数)
renderComponent( this );//调用render渲染组件
}
В этой реализации каждый вызовsetState
будет обновлять состояние и отображать его один раз (не в соответствии с его механизмом оптимизации обновления), поэтому мы должны объединитьsetState
.
Для получения подробной информации вы можете прочитать исходный кодReactUpdateQueue.js
react
Реализация сделки в
быть улучшенным Это выглядит немного запутаннымАнализ исходного кода React (3): подробная транзакция и очередь обновлений Транзакции в React Механизм транзакций React
транзакция транзакция
ErrorBoundary
,Suspense
а такжеFragment
Error Boundaries
react 16 предоставляет новый хук для перехвата ошибокcomponentDidCatch(error, errorInfo)
, который может фиксировать ошибки, возникающие в жизненном цикле дочерних компонентов, и предотвращать глобальный сбой страницы. демоcomponentDidCatch
не ловит следующие ошибки
- Ошибки, выдаваемые механизмом событий (ошибки в событиях не влияют на отрисовку)
- Ошибки, выдаваемые самими границами ошибок
- Асинхронно генерируемые ошибки
- рендеринг на стороне сервера
lazy、Suspence
Ленивая загрузка компонентов
lazy
нужно следоватьSuspence
Используйте вместе, иначе будет сообщено об ошибке.
lazy
На самом деле, это помогает нам добиться разделения кода, аналогичного веб-пакету.splitchunk
функция.
Suspense
Это означает, что рендеринг текущего компонента можно приостановить и возобновить рендеринг, когда что-то будет сделано. Проще говоря, это уменьшение размера кода в верхней части страницы и повышение производительности.
import react, { lazy, Suspense } from 'react'
const OtherComponent = lazy(() => import('./OtherComponent'))
function MyComponent() {
return (
<Suspense fallback={<div>loading...</div>}>
<OtherComponent />
</Suspense>
)
}
Простая идея предварительной загрузки, пожалуйста, обратитесь к предварительной загрузке
const OtherComponentPromise = import('./OtherComponent')
const OtherComponent = react.lazy(() => OtherComponentPromise)
Fragments(v16.2.0)
Фрагменты позволяют группировать подсписки, чтобы избежать дополнительных узлов в DOM.
render() {
return (
<>
<ChildA />
<ChildB />
<ChildC />
</>
);
}
react Fiber
Анализ архитектуры
react-fiber
Это сделано для повышения применимости анимации, макета и мобильных жестов. Наиболее важной функцией является оптимизация рендеринга страницы: это позволяет разделить работу рендеринга на несколько сегментов.
react Fiber
какую проблему решает архитектура
react-fiber
Он может предоставить нам следующие функции:
- Установить приоритет задач рендеринга
- Использование нового алгоритма Diff
- Использование дизайна виртуального стека позволяет переключаться между задачами рендеринга с более высоким приоритетом и задачами с более низким приоритетом.
Fiber
Как сделать асинхронный рендерингVirtual Dom
а такжеDiff
алгоритм
Как мы все знаем, экран обновляется 60 раз в секунду, и страница выглядит гладкой для человеческого глаза без явных задержек. Страница должна обновляться 60 раз в секунду, то есть 16 мс.Если время обновления страницы меньше 16 мс, останется немного времени для выполнения других задач до следующего времени обновления, пока интерфейс обновляется по времени с интервалом в 16мс, на плавность страницы никак не повлияет. Ядро оптоволокна использует принцип 60 кадров для реализации циклического алгоритма планирования задач на основе приоритета и requestIdleCallback.
function fiber(剩余时间) {
if (剩余时间 > 任务所需时间) {
做任务
} else {
requestIdleCallback(fiber)
// requestIdleCallback 是浏览器提供的一个 api,可以让浏览器在空闲的时候执行回调,
// 在回调参数中可以获取到当前帧剩余的时间,fiber 利用了这个参数,
// 判断当前剩下的时间是否足够继续执行任务,
// 如果足够则继续执行,否则暂停任务,
// 并调用 requestIdleCallback 通知浏览器空闲的时候继续执行当前的任务
}
}
react hooks
До версии 16.7 реакция имела две формы компонентов: компоненты с состоянием (классы) и компоненты без состояния (функции). Официальное объяснение: Hook — это новая функция React 16.8. Он позволяет использовать состояние и другие функции React без написания классов. Личное понимание: пусть традиционный функциональный компонент функциональный компонент имеет функциональную функцию внутреннего состояния состояния, короче говоря, крючки заставляют функциональный компонент иметь состояние, которое может полностью заменить класс.
Затем разберитесь с двумя основными API в Hooks,useState
а такжеuseEffect
useState
useState — это хук, который может добавить некоторое состояние к функциональному компоненту и предоставить функции для изменения этих состояний, и он принимает параметр, который является значением состояния по умолчанию.
const [count, setCount] = useState(initialState)
Самое интуитивное ощущение от использования хуков заключается в том, что они более лаконичны, чем предыдущий метод написания класса
function App() {
const [count, setCount] = useState(0)
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
)
}
useEffect(fn)
Этот хук выполняется после каждого рендера. рассматривать это какcomponentDidMount
,componentDidUpdate``、componentWillUnmount
коллекция. Так что используйтеuseEffect
Преимущества перед предыдущими:
можно избежать вcomponentDidMount
,componentDidUpdate
писать повторяющийся код;
Ассоциативную логику можно записать вuseEffect
(Раньше его нужно было записывать в разные жизненные циклы);
Глубокое понимание принципов реагирования
Разбор принципа реагирующего виртуального дома
Процесс рендеринга компонентов реакции
использоватьreact.createElement
Или напишите реагирующие компоненты в JSX, фактически весь код JSX в конечном итоге будет преобразован вreact.createElement(...)
, Babel помог нам с этим процессом преобразования.
Функция createElement обрабатывает специальные реквизиты, такие как ключ и ссылка, и получаетdefaultProps
Назначьте значения свойствам по умолчанию, обработайте входящие дочерние узлы и, наконец, создайтеreactElement
объекты (так называемый виртуальный DOM).
reactDOM.render
Визуализировать сгенерированный виртуальный DOM в указанный контейнер, который использует пакетную обработку, транзакции и другие механизмы, выполняет оптимизацию производительности для определенных браузеров и, наконец, преобразует его в настоящий DOM.
Состав виртуального DOM
которыйreactElementelement
Объекты, наши компоненты в конечном итоге будут отображаться в следующую структуру:
`type`:元素的类型,可以是原生 html 类型(字符串),或者自定义组件(函数或 class)
`key`:组件的唯一标识,用于 Diff 算法,下面会详细介绍
`ref`:用于访问原生 dom 节点
`props`:传入组件的 props,chidren 是 props 中的一个属性,它存储了当前组件的孩子节点,可以是数组(多个孩子节点)或对象(只有一个孩子节点)
`owner`:当前正在构建的 Component 所属的 Component
`self`:(非生产环境)指定当前位于哪个组件实例
`_source`:(非生产环境)指定调试代码来自的文件(fileName)和代码行数(lineNumber)
Когда состояние компонента изменяется, реакция автоматически вызывает метод рендеринга компонента для повторного рендеринга всего пользовательского интерфейса компонента.
Конечно, если вы действительно работаете с DOM в такой большой области, производительность будет большой проблемой, поэтому react реализуетVirtual DOM
, структура DOM компонента сопоставляется с этимVirtual DOM
на, реагировать в этомVirtual DOM
Алгоритм diff реализован на основе вышеизложенного.Когда компонент должен быть перерендерен, DOM-узел, который нужно изменить, будет найден через diff, а затем модификация будет обновлена до фактического DOM-узла браузера, поэтому он на самом деле не отображает все дерево DOM. этоVirtual DOM
Это чистая структура данных JS, поэтому производительность будет намного выше, чем у нативной DOM.
react
как предотвратитьXSS
из
reactElement
объект имеет другой?typeof
свойство, которое является переменной типа SymbolSymbol.for('react.element')
, когда среда не поддерживает Symbol ,?typeof
назначается как0xeac7
.
Эта переменная предотвращает XSS. Если на вашем сервере есть уязвимость, которая позволяет пользователям хранить произвольные объекты JSON, в то время как код на стороне клиента ожидает строку, это может представлять риск для вашего приложения. нельзя хранить в JSONSymbol
переменная типа и реагирует на нее без\$\$typeof
Идентифицированные компоненты отфильтровываются.
diff
алгоритм
традиционныйdiff
Алгоритм сравнивает узлы один раз через рекурсию, и эффективность очень низкая.Сложность алгоритма достигает O(n^3), где n — общее количество узлов в дереве.React формулирует смелую стратегию по снижению сложности O (n^3) Задача трансформируется в задачу сложности O(n).
diff
Стратегия:
- В веб-интерфейсе есть несколько операций межуровневого перемещения узлов Dom,
diff
Когда алгоритм сравнивает старые и новые узлы, сравнение будет выполняться только на одном уровне, а не между уровнями. - Два компонента с одним и тем же классом будут генерировать похожие древовидные структуры, а два компонента с разными классами будут генерировать разные древовидные структуры.
- Для группы дочерних узлов одного уровня их можно отличить по уникальному ключу.
Основываясь на трех вышеупомянутых стратегиях, Reacttree diff
,component diff
так же какelement diff
Для оптимизации алгоритма факты также доказывают, что эти три исходные стратегии разумны и точны, что гарантирует производительность всей конструкции интерфейса.
Проще говоря:
Для получения подробной информации см.Серия анализа исходного кода React - невероятная реакция diff
- React преобразует проблемы сложности O (n3) в проблемы сложности O (n), формулируя смелую стратегию сравнения;
- React использует стратегию иерархической дифференциации,
tree diff
Оптимизация алгоритма; - React генерирует похожие древовидные структуры через один и тот же класс, а разные классы генерируют разные древовидные структуры.
component diff
Оптимизация алгоритма; - React отвечает стратегии установки уникального ключа
element diff
Оптимизация алгоритма;
Рекомендуется, чтобы при разработке компонентов поддержание стабильной структуры DOM помогло повысить производительность; В процессе разработки рекомендуется свести к минимуму операцию перемещения последнего узла в заголовок списка.Когда количество узлов слишком велико или операция обновления слишком частая, это в определенной степени повлияет на производительность рендеринга React. .
исходный код snabdom, как реализовать упрощенный виртуальный DOM
Быть добавленным
Анализ и оптимизация производительности React
Уменьшите ненужный рендеринг
В использованииclass Component
При разработке мы можем использоватьshouldComponentUpdate
Чтобы уменьшить ненужное рендеринг, затем использоватьreact hooks
Как после этого реализовать такую функцию?
решение:React.memo
а такжеuseMemo
В этой ситуации реакция, конечно, также дает официальное решение, которое заключается в использовании React.memo и useMemo.
React.memo
React.momo на самом деле не является хуком, он фактически эквивалентен PureComponent, но он только сравнивает свойства. Он используется следующим образом (на примере выше):
import React, { useState } from 'react'
export const Count = React.memo(props => {
const [data, setData] = useState({
count: 0,
name: 'cjg',
age: 18
})
const handleClick = () => {
const { count } = data
setData({
...data,
count: count + 1
})
}
return <button onClick={handleClick}>count:{data.count}</button>
})
useMemo
Использование useMemo на самом деле немного похоже на useEffects, давайте посмотрим непосредственно на официальный пример.
function Parent({ a, b }) {
// Only re-rendered if `a` changes:
const child1 = useMemo(() => <Child1 a={a} />, [a])
// Only re-rendered if `b` changes:
const child2 = useMemo(() => <Child2 b={b} />, [b])
return (
<>
{child1}
{child2}
</>
)
}
Как видно из примера, его второй параметр совпадает со вторым параметром useEffect, только при изменении значения второго массива параметров будет срабатывать обновление дочернего компонента.
ЦитироватьРеактивные хуки на практике
Используйте shouldComponentUpdate() для предотвращения ненужного повторного рендеринга.
Когда реквизиты или состояние компонента изменяются, React сравнивает только что возвращенный элемент с ранее визуализированным элементом, чтобы определить, необходимо ли обновлять реальный DOM, и обновит DOM, если они не совпадают.
Несмотря на то, что React обновляет только измененные узлы DOM, повторный рендеринг все равно занимает некоторое время. В большинстве случаев это не проблема, но если рендерится много компонентов, возникнут проблемы с производительностью, мы можем ускорить ее, переопределив метод жизненного цикла shouldComponentUpdate.
Метод shouldComponentUpdate будет запущен перед повторным рендерингом. Его реализация по умолчанию всегда возвращает true, если компонент не нуждается в обновлении, вы можете вернуть false в shouldComponentUpdate, чтобы пропустить весь процесс рендеринга. Он включает в себя вызов рендеринга компонента и последующие действия.
shouldComponentUpdate(nextProps, nextState) {
return nextProps.next !== this.props.next
}
Анализатор производительности React
В React 16.5 добавлена поддержка нового плагина профилирования DevTools. Этот плагин использует экспериментальный API-интерфейс React Profiler для сбора информации о времени рендеринга каждого компонента, чтобы выявить узкие места производительности в приложениях React. Он будет полностью совместим с нашими будущими функциями разделения времени (временного разделения) и саспенса (зависания).
redux
Store
: место для сохранения данных, вы можете думать о нем как о контейнере, все приложение может иметь только одинStore
.
State
:Store
Объект содержит все данные, если вы хотите получить данные в определенный момент времени, вам нужноStore
Создайте снимок, набор данных на данный момент времени, называемыйState
.
Action
:State
изменения приведут к изменениям в представлении. Однако пользователь не может касаться состояния, только представления. Следовательно, изменение состояния должно быть вызвано представлением. Действие — это уведомление, отправленное представлением, указывающее, что состояние должно измениться.
Action Creator
: Сколько видов сообщений View хочет отправитьAction
. Будет очень хлопотно, если все будет написано вручную, поэтому мы определяем функцию для генерации Action, эта функция называетсяAction Creator
.
Reducer
:Store
получатьAction
Позднее появился новыйState
, так что представление изменится. этоState
Процесс расчета называетсяReducer
.Reducer
это функция, которая принимает действие и текущийState
В качестве аргумента возвращает новыйState
.
dispatch
:ДаView
проблемаAction
единственный способ.
Основы редукса
Затем проходим весь рабочий процесс:
Во-первых, пользователь (черезView
)проблемаAction
, используется метод выдачиdispatch
метод.
Потом,Store
автоматический вызовReducer
и передать два параметра: текущийState
и получилAction
,Reducer
вернется новыйState
State
Как только происходит изменение,Store
Функция прослушивателя будет вызываться для обновленияView
.
На этом процесс взаимодействия с пользователем заканчивается. Видно, что данные текут в одном направлении на протяжении всего процесса, что обеспечивает наглядность процесса.
redux
Как спроектировать архитектуру одностороннего потока данных
быть улучшенным
redux
промежуточное ПО
Промежуточное программное обеспечение Redux обеспечивает точку расширения до того, как редуктор будет достигнут после инициации действия.Другими словами, исходный поток данных: представление -> действие -> редуктор -> хранилище плюс промежуточное ПО становится представлением -> действие -> промежуточное ПО -> reducer -> store , в этой ссылке мы можем выполнять некоторые операции с «побочными эффектами», такие как асинхронные запросы, печать логов и т. д.
Промежуточное программное обеспечение Redux реализует перехват действия -> редуктора, переписывая метод store.dispatch.Из приведенного выше описания можно более четко понять модель промежуточного программного обеспечения Redux:
中间件A -> 中间件B-> 中间件C-> 原始 dispatch -> 中间件C -> 中间件B -> 中间件A
Это также напоминает нам, что при использовании промежуточных программ мы должны обратить внимание, когда промежуточное программное обеспечение «делает вещи». Например, Redux-Thunk перехватывает действие функции типа перед выполнением следующего (действие), а redux-Saga находится в следующем ( Действие) будет вызвать мониторинг Sagaemitter.emit (Action) и не перехватят существующие действия от достижения редуктора.
Ссылаться на:
- Углубленный анализ принципа рендеринга и характеристик виртуального DOM
- механизм событий реакции
- От миксинов до HOC и хуков
- Техническая команда Meituan-Redux от дизайна до исходного кода
- Разберите исходный код snabbdom и научитесь реализовывать упрощенную библиотеку Virtual DOM.
- Реагировать на анализ исходного кода
- Грубое сравнение двух фреймворков Vue и React