предисловие
существуетReact Conf 2018В ходе встречи Дэн Абрамов представилReact Hooks. Официальное описание
Хуки — это новая функция, позволяющая использовать состояние и другие функции React без написания классов. В настоящее время они находятся в React v16.7.0-alpha. Основной релиз запланирован на первый квартал 2019 года.
Болевые точки
Ниже приведена функция мотивации React Hooks, которая решает некоторые проблемы в существующем React.
Общее состояние между жестким компонентом
В React нет способа привязать повторно используемое поведение к компонентам (например, ссылку на магазин). Если вы использовали его некоторое время, вы можете использоватьrender props
а такжеheight-order components
Компоненты решают эту проблему. Но эти шаблоны требуют рефакторинга компонентов при их повторном использовании, что может быть обременительно. если вы используетеReact DevTools
Взгляните на свою программу, и вы обнаружите, что ваши компоненты обернуты различными компонентами, называемыми областями-оболочками, такими как: поставщики, потребители, компоненты более высокого порядка, реквизиты рендеринга и т. д. Здесь есть более глубокая фундаментальная проблема: React нуждается в лучшем способе совместного использования логики состояния.
ЭтоHooks
, вы можете извлечь логику с отслеживанием состояния из компонентов, чтобы их можно было независимо протестировать и повторно использовать.Hooks
Позволяет повторно использовать логику с отслеживанием состояния без изменения иерархии компонентов. Это упрощает обмен данными между несколькими компонентами или с сообществом.Hooks
.
Компоненты становятся все более сложными и трудными для понимания
Нам часто приходится поддерживать компоненты, которые изначально были простыми и со временем превращались в кучу неуправляемой логики с отслеживанием состояния и побочных эффектов. Каждый метод жизненного цикла часто содержит несвязанные комбинации логики. Например, компонент может находиться вcomponentDidMount
а такжеcomponentDidUpdate
вытащить некоторые данные. а такжеcomponentDidMount
Метод также может содержать некоторую несвязанную логику для прослушивателей событий и размонтировать прослушиватели в componentWillUnmount`. Но совершенно несвязанный код объединяется в один метод. склонен к ошибкам и несоответствиям.
Во многих случаях эти компоненты невозможно разделить на более мелкие компоненты, поскольку логика разбросана по многим местам. Проверить их тоже сложно. Вот почему так много людей используют React с библиотеками управления состоянием. Но проще создать больше абстракций, требующих переключения между множеством разных файлов, и будет сложнее повторно использовать компоненты.
Для решения этой проблемы,Hooks
Позволяет разделить их на меньшую функцию на основе связанных функций. Вместо принудительного разделения на основе функции периода объявления. Вы также можете использовать редюсер для управления локальным состоянием компонента, что сделает его более предсказуемым.
Люди и машины путаются
Помимо усложнения повторного использования и организации кода, мы обнаружили, что классы (classes
) может стать большим препятствием для изучения React. Вы должны понимать, как это работает в JavaScript, что сильно отличается от того, как это работает в большинстве языков. Вы должны понимать, как правильно привязывать обработку событий и пока еще не стабильнуюновый синтаксис, код очень подробный. Может быть легко понять свойства (реквизиты), состояние (состояние), поток данных сверху вниз (поток данных сверху вниз), но классы (классы) понять сложно. Разница между компонентами функций и классов в React и когда их использовать приводит к разногласиям даже среди опытных разработчиков React. Используя функцию, которую вы можете использоватьprepackБолее оптимизированный код. Но использование компонентов класса не может быть лучше оптимизировано.
Чтобы решить эти проблемы, хуки позволяют вам использовать больше функций React без классов.
useState
useState
Вы можете сделать так, чтобы ваши функциональные компоненты также имели функцию состояния компонентов класса.
Синтаксис использования следующий:
const [state, setState] = useState(initialState);
useState
Возвращает массив, одно из которых является значением состояния, а второе — функцией, которая обновляет состояние
В реальной программе мы можем использовать это так:
function TestUseState() {
const [count, setCount] = React.useState(0);
return (
<div>
<p>useState api</p>
<p>Count: {count} <button onClick={() => setCount(count + 1) }>自增</button></p>
</div>
)
}
использоватьuseState
Одна вещь, на которую следует обратить внимание при инициализации, — это объект. использоватьsetCount
Это не похоже на компонент классаthis.setState
будут автоматически объединены в состояние.setCount
Заменяет предыдущее состояние текущим значением. Следующим образом
function TestUseStateObject() {
const [state, setState] = React.useState({
count: 0,
greeting: "Hello, World!",
});
const handleAdd = () => {
setState({
count: state.count + 1
})
}
console.log('state > ', state)
return (
<div>
<p>useStateObject api</p>
<p>Count: {state.count} <button onClick={handleAdd}>自增</button></p>
</div>
)
}
Мы видим, что состояние заменяется на {count: 1} при нажатии кнопки. Если вы хотите использовать объект в состоянии, вам необходимо деконструировать предыдущее значение при обновлении значения следующим образом:
setState({
...state,
count: state.count + 1
})
Использование нескольких состояний в функции
function TestMultipleUseState() {
const [count, setCount] = React.useState(0);
const [name, setName] = React.useState('john');
return (
<div>
<p>useState api</p>
<p>Count: {count} - Name: {name}</p>
</div>
)
}
Для онлайн-теста перейдите по ссылкеcodepen useState
useEffect
по умолчаниюuseEffect
Запускается после завершения рендеринга, где мы можем получить DOM и обработать другие побочные эффекты. Но у него также есть две разные фазы работы, которые я объясню позже.
function TestUseEffect() {
const [count, setCount] = React.useState(0);
React.useEffect(() => {
console.log(`组件被更新,Count: ${count}`);
});
return (
<div>
<p>useEffect api</p>
<p>Count: {count} <button onClick={() => setCount(count + 1) }>自增</button></p>
</div>
)
}
надuseEffect
Запускается после рендеринга каждого компонента, каждый раз, когда мы нажимаем кнопку автоинкремента.
Но если приведенный выше код выполняется после каждого рендера, если мы находимся вuseEffect
Вытягивать данные с сервера. В результате данные извлекаются с сервера после каждого рендеринга. или только некоторыеprops
Хотите выполнить после обновленияuseEffect
. тогда по умолчаниюuseEffect
это не то, как мы хотим выступать, тоuseEffect
Предусмотрен второй параметр.
useEffect(didUpdate, [])
useEffect
Второй параметр — это массив. Когда мы предоставляем второй параметр, изменяется только второй параметрuseEffect
будет казнен. Используя второй параметр, мы можем имитировать компонент класса.componentDidMount
функция жизненного цикла
function TestUseEffectListener() {
const [count, setCount] = React.useState(0);
React.useEffect(() => {
console.log('componentDidMount fetch Data...');
}, []);
return (
<div>
<p>TestUseEffectListener</p>
<p>Count: {count} <button onClick={() => setCount(count + 1) }>自增</button></p>
</div>
)
}
в коде вышеuseEffect
будет выполняться только один раз, когда вы нажмете автоинкрементuseEffect
И не будет он выполнен снова.
существуетuseEffect
В функции первого параметра мы можем вернуть функцию для выполненияфункция очистки, он будет выполнен до очистки компонента пользовательского интерфейса в сочетании с полученными выше знаниями.useEffect
моделированиеcomponentWillUnmount
функция жизненного цикла
function TestUseEffectUnMount() {
const [count, setCount] = React.useState(0);
React.useEffect(() => {
return () => {
console.log('componentUnmount cleanup...');
}
}, []);
return (
<div>
<p>TestUseEffectUnMount</p>
</div>
)
}
В приведенном выше коде, когда компонентTestUseEffectUnMount
Будет выполнен, когда он вот-вот будет уничтоженconsole.log('componentUnmount cleanup...')
код
Для онлайн-теста перейдите по ссылкеcodepen useEffect
useContext
useContext
позволяет использовать в функцииcontext
, что эффективно решает предыдущуюProvider
,Consumer
Вопросы, требующие дополнительных компонентов упаковки
Синтаксис использования следующий:
const context = useContext(Context);
Теперь посмотрим на это на практикеuseContext
Как использовать, код выглядит следующим образом:
function TestFuncContext() {
const context = React.useContext(ThemeContext);
return (
<div style={context}>TestFuncContext</div>
)
}
Мы видим, что вышеприведенное напрямую используетReact.useContext(ThemeContext)
вы можете получитьcontext
, тогда как в предыдущих версиях нужно было получить что-то вроде этого<Consumer>({vlaue} => {})</Consumer>
, что значительно упрощает написание кода.
// 之前Consumer的访问方式
function TestNativeContext() {
return (
<ThemeContext.Consumer>
{(value) => {
return (
<div style={value}>TestNativeContext</div>
)
}}
</ThemeContext.Consumer>
);
}
Для онлайн-теста перейдите по ссылкеcodepen useContext
useReducer
useReducer
даuseState
программа условного депонирования. Используйте его, когда у вас есть более ответственные данные.
Синтаксис использования следующий:
const [state, dispatch] = useReducer(reducer, initialState)
Первый параметр — это сокращение для обработки входящего действия.Объявление функции:(state, action) => ()
. Второй параметр — инициализированная константа состояния.
в возвращаемом значении[state, dispatch]
, состояние — ваши данные. диспетчеризация может инициировать действие, которое будет обработано в редюсере.
Эта функция дает мне ощущение, что компонент является локальным редуксом, и это хорошо. При проектировании могут использоваться некоторые сложные структуры данных.
Теперь посмотрим на это на практикеuseReducer
Как использовать, код выглядит следующим образом:
function TestUseReducer() {
const [state, setState] = React.useReducer((state, action) => {
switch(action.type) {
case 'update':
return {name: action.payload}
default:
return state;
}
}, {name: ''});
const handleNameChange = (e) => {
setState({type: 'update', payload: e.target.value})
}
return (
<div>
<p>你好:{state.name}</p>
<input onChange={handleNameChange} />
</div>
)
}
Когда значение на входе изменяется, данные в состоянии будут обновляться одновременно, а затем отображаться в интерфейсе.
Для онлайн-теста перейдите по ссылкеcodepen useReducer
useCallback
useCallback
а такжеuseMemo
несколько похоже. Он принимает встроенную функцию и массив, который возвращаетзапоминаниефункция версии.
Синтаксис использования следующий:
const memoizedValue = useMemo(() => computeExpensiveValue(a), [a])
useCallback
Первый параметр — это функция для выполнения некоторых операций и вычислений. Второй параметр - это массив, когда значение в этом массиве меняетсяuseMemo
Повторно выполнит и обновит анонимную функцию, на которую ссылаетсяa
ценность . Это описание может быть немного сложным для понимания. Давайте рассмотрим пример:
function TestUseCallback({ num }) {
const memoizedCallback = React.useCallback(
() => {
// 一些计算
return num;
},
[],
);
console.log('记忆 num > ', memoizedCallback())
console.log('原始 num > ', num);
return (
<div>
<p>TestUseCallback</p>
</div>
)
}
Если мы хотим контролироватьnum
Обновление значения снова выполняет некоторые операции и вычисления, мы можем указать второй параметрnum
значение, например:
function TestUseCallback({ num }) {
const memoizedCallback = React.useCallback(
() => {
// 一些计算
return num;
},
[num],
);
console.log('记忆 num > ', memoizedCallback())
console.log('原始 num > ', num);
return (
<div>
<p>TestUseCallback</p>
</div>
)
}
Для онлайн-теста перейдите по ссылкеcodepen useCallback
useRef
я думаюuseRef
Функции немного похожи на свойство класса, или, скажем, вы хотите записать некоторые значения в компонент, и эти значения можно изменить позже.
Синтаксис использования следующий:
const refContainer = useRef(initialValue)
useRef
Возвращает изменяемый объект, объектcurrent
Свойства инициализируются переданным параметром (initialValue). Возвращенный объект будет сохраняться в течение всего времени существования компонента.
Программа, которая сохраняет элемент ввода и переводит его в фокус, код выглядит следующим образом:
function TestUseRef() {
const inputEl = React.useRef(null);
const onButtonClick = () => {
// 点击按钮会设置input获取焦点
inputEl.current.focus(); // 设置useRef返回对象的值
};
return (
<div>
<p>TestUseRef</p>
<div>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>input聚焦</button>
</div>
</div>
)
}
useRef
Вы можете установить возвращаемый объект в других местах, таких как: useEffect, useCallback и т. д.
Для онлайн-теста перейдите по ссылкеcodepen useRef
Спасибо за чтение 🙏
Наконец, чтобы сделать объявление, я создалЕженедельный интерфейсПоследние технические статьи и проекты с открытым исходным кодом выходят каждую пятницу Добро пожаловать на подписку