Новое в React 16.7-альфа:Hooks
. Подводя итог, его функция:FunctionalComponent
имеютClassComponent
функция.
import React, { useState, useEffect } from 'react'
function FunComp(props) {
const [data, setData] = useState('initialState')
function handleChange(e) {
setData(e.target.value)
}
useEffect(() => {
subscribeToSomething()
return () => {
unSubscribeToSomething()
}
})
return (
<input value={data} onChange={handleChange} />
)
}
согласно сDanаргумент, дизайнHooks
главным образом для решенияClassComponent
Несколько вопросов:
- Сложно повторно использовать логику (используйте только HOC или реквизиты рендеринга), что приведет к глубокой иерархии дерева компонентов.
- Будет генерировать огромные компоненты (это означает, что в классе должно быть написано много кода)
- Компоненты класса сложны для понимания, как методы требуют
bind
,this
Пункт не ясен
Это действительно проблемы, например, если мы используемreact-router
+redux
+material-ui
, вполне вероятно, что какой-либо компонент окажетсяexport
Код, который выходит, — фиолетовый соус:
export default withStyle(style)(connect(/*something*/)(withRouter(MyComponent)))
Это 4-уровневый вложенныйHOC
компоненты
В то же время, если в вашем компоненте много событий, то вашconstructor
В нем может быть фиолетово:
class MyComponent extends React.Component {
constructor() {
// initiallize
this.handler1 = this.handler1.bind(this)
this.handler2 = this.handler2.bind(this)
this.handler3 = this.handler3.bind(this)
this.handler4 = this.handler4.bind(this)
this.handler5 = this.handler5.bind(this)
// ...more
}
}
Хотя последниеclass
можно использовать грамматикуhandler = () => {}
Приходите к связыванию быстро, но это также решает проблему объявления, и общая сложность все еще существует.
Тогда естьcomponentDidMount
а такжеcomponentDidUpdate
подписаться на контент вcomponentWillUnmount
В коде отписки в . Самое главное, вClassComponent
Код метода жизненного цикла сложно повторно использовать в других компонентах, что приводит к проблеме низкой скорости повторного использования кода.
И естьclass
Код трудно сжать для инструментов упаковки, таких как имена методов.
Для получения более подробной информации вы можете перейти наReactConf
видео, тут много говорить не буду,Тема этой статьи — поговорить об этом с точки зрения исходного кода.Hooks
как это достигается
Давайте сначала разберемся с некоторыми основными понятиями
первыйuseState
это метод, который сам не может хранить состояние
Во-вторых, он бежитFunctionalComponent
Внутри само состояние не может быть сохранено.
useState
принимает только один параметрinitial value
, и не вижу ничего особенного. Так как же React получает ранее обновленный при повторном рендерингеstate
Шерстяная ткань?
Прежде чем приступить к объяснению исходного кода, мы должны сначала установить некоторые понятия:
React Element
JSX
После перевода этоReact.createElement
, он в конце концов возвращаетReactElement
объект, его данные деструктурируются следующим образом:
const element = {
?typeof: REACT_ELEMENT_TYPE, // 是否是普通Element_Type
// Built-in properties that belong on the element
type: type, // 我们的组件,比如`class MyComponent`
key: key,
ref: ref,
props: props,
// Record the component responsible for creating this element.
_owner: owner,
};
При этом следует отметить, чтоtype
, после того как напишем<MyClassComponent {...props} />
, его значениеMyClassComponent
этоclass
, а не его экземпляр, который создается при последующем рендеринге.
Fiber
Каждый узел будет иметь соответствующийFiber
объект, его данные деструктурируются следующим образом:
function FiberNode(
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
) {
// Instance
this.tag = tag;
this.key = key;
this.elementType = null; // 就是ReactElement的`?typeof`
this.type = null; // 就是ReactElement的type
this.stateNode = null;
// Fiber
this.return = null;
this.child = null;
this.sibling = null;
this.index = 0;
this.ref = null;
this.pendingProps = pendingProps;
this.memoizedProps = null;
this.updateQueue = null;
this.memoizedState = null;
this.firstContextDependency = null;
// ...others
}
Здесь нужно обратить вниманиеthis.memoizedState
,этоkey
Он используется для хранения узла, окончательно полученного в последнем процессе рендеринга.state
Да, каждый раз, когда вы выполняетеrender
Перед методом React рассчитает последнюю версию текущего компонента.state
затем назначьтеclass
экземпляр, затем позвонитеrender
.
Поэтому многие студенты, которые не очень хорошо разбираются в принципах React, узнают о React.ClassComponent
неправильно понять, подуматьstate
а такжеlifeCycle
Они все называются сами по себе, потому что мы унаследовалиReact.Component
, в нем должно быть много связанной логики. На самом деле, если вам интересно, вы можете проверить это.Component
Исходный код, вероятно, более 100 строк, очень прост. Итак, в Реактеclass
Это просто носитель, что облегчает понимание, когда мы пишем компоненты.class
закрыты
принцип
Зная вышеизложенные основы, дляHooks
Принцип того, почему компоненты без состояния могут быть сохранены, лучше понят.
Предположим, у нас есть этот фрагмент кода:
function FunctionalComponent () {
const [state1, setState1] = useState(1)
const [state2, setState2] = useState(2)
const [state3, setState3] = useState(3)
}
Первый взгляд на картинку
в нашей реализацииfunctionalComponent
, когда первое выполнениеuseState
, он будет соответствоватьFiber
на объектеmemoizedState
, который изначально был предназначен для храненияClassComponent
изstate
, потому что вClassComponent
серединаstate
представляет собой цельный объект, поэтому его можно комбинировать сmemoizedState
Переписка один на один.
Но когдаHooks
, React не знает, сколько раз мы вызывалиuseState
, так что экономияstate
В этом вопросе React придумал более интересное решение, которое заключается в вызовеuseState
установить послеmemoizedState
Вышеупомянутый объект выглядит следующим образом:
{
baseState,
next,
baseUpdate,
queue,
memoizedState
}
мы зовем егоHookобъект. Здесь нам следует больше всего беспокоитьсяmemoizedState
а такжеnext
,memoizedState
используется для записи этогоuseState
должен вернуть результат, аnext
указывая на следующий разuseState
Соответствующий объект `Hook.
То есть:
hook1 => Fiber.memoizedState
state1 === hook1.memoizedState
hook1.next => hook2
state2 === hook2.memoizedState
hook2.next => hook3
state3 === hook2.memoizedState
каждый вFunctionalComponent
называется вuseState
будет соответствующийHook
Объекты, они хранятся в формате данных в виде связанного списка в порядке выполнения.Fiber.memoizedState
начальство
Вот в чем дело: потому что так делаетсяstate
хранение, такuseState
(включая другие хуки) должны быть вFunctionalComponent
объявляется в корневой областиif
или объявлен в цикле, например
if (something) {
const [state1] = useState(1)
}
// or
for (something) {
const [state2] = useState(2)
}
Основная причина в том, что вы не можете гарантировать, что эти условные операторы каждый раз будут выполняться одинаковое количество раз., то есть если мы первый раз создадимstate1 => hook1, state2 => hook2, state3 => hook3
После такой переписки следующая казнь полагаетсяsomething
условия не выполняются, что приводит кuseState(1)
не выполняется, то запуститеuseState(2)
когда вы получаетеhook
объектstate1
, то вся логика перепутана,Так что это условие необходимо соблюдать!
setState
сказано вышеHooks
серединаstate
Как сохранить, тогда поговорим о том, как обновитьstate
вызов, который мы называемuseState
Способ возврата фиолетовый:
var dispatch = queue.dispatch = dispatchAction.bind(null, currentlyRenderingFiber$1, queue);
return [workInProgressHook.memoizedState, dispatch];
Вызов этого метода создаетupdate
var update = {
expirationTime: _expirationTime,
action: action,
callback: callback !== undefined ? callback : null,
next: null
}
здесьaction
это то, что мы называемsetState1
переданное значение, и этоupdate
будет добавлено кqueue
, потому что одновременно может быть несколько вызововsetState1
Опустошение (связанное с пакетным обновлением React, у меня будет возможность поговорить об этом позже).
Собрав все этоupdate
После этого он будет назначен один разReact
Обновление, в процессе обновления, обязательно будет внедрено в нашуFunctionalComponent
, то соответствующийuseState
, и тогда мы получимHook
объект, он спасqueue
Объект указывает, какие обновления существуют, а затем обновляет их по очереди, чтобы получить последниеstate
Сохранить какmemoizedState
вверх и обратно, наконец достигнувsetState
Эффект.
Суммировать
На самом деле, сClassComponent
почти то же самое, только потому, чтоuseState
разделить один объектstate
, поэтому вам нужно сохранять данные относительно уникальным способом, и будут определенные правила и ограничения.
Но эти условия никак нельзя скрытьHooks
Свет, который он имел в виду, был слишком велик, чтобы позволитьReact
этофункциональное программированиеФреймворки Paradigm наконец-то избавились от неудобной сцены использования классов для создания компонентов. На самом деле существование классов действительно не имеет смысла, напримерPuerComponent
Сейчас есть соответствующиеReact.memo
Чтобы сделать функциональные компоненты можно добиться того же эффекта.
Наконец, поскольку мы действительно хотим распространять исходный код, он будет включать в себя некоторый другой контент исходного кода, такой какworkInProgress => current
конверсия,expirationTime
Задействованное планирование и т. д. заставят всех не понять основную часть этой статьи.Hooks
, поэтому после того, как я написал полный анализ исходного кода, я обобщил эту статью и выпустил ее отдельно. Надеюсь, это поможет вам лучше понятьHooks
, и его можно смело использовать в реальных разработках.
Потому что: это действительно полезно! ! !
Уведомление
В настоящее времяreact-hot-loader
не может иhooks
использовать вместе,Подробности, так что вы можете подождать до официального релиза.
Я Джоки, фронтенд-инженер, который фокусируется на навыках React и глубоком анализе React определенно является фреймворком, который чем больше вы изучаете, тем больше вы чувствуете, что его дизайн сложный и думает наперед. Подписывайтесь на меня, чтобы получать последние новости о React и самые глубокие знания о React.Больше статей здесь