Введение
Позвольте сначала задать вам несколько вопросов. Это все вопросы, которые мне задавали в интервью. Если они верны, я не смогу их исправить. …
- Писать
hooks
По сравнению с написанием компонентов класса,hooks
Каковы преимущества? - Как мы инкапсулируем
hook
? -
hooks
Каков принцип?
Хоть интервью и холодное, учеба должна продолжаться😭
Два углубленных понимания хуков
useState
- использовать
useState
Использование очень просто🙉, после предложения возвращает массив, значением массива является текущийstate
и обновитьstate
Функция;useState
Параметрыпеременная, объект или функция, переменная или объект будут использоваться какstate
Начальное значение , если это функция, возвращаемое значение функции будет использоваться как начальное значение.
- Массовое обновление
Посмотрите на код ниже
function Count(){
let [count,setCount] = useState(0)
const handleAdd = function(){
setCount(count+1)
setCount(count+1)
}
return(
<div>
<p>{count}</p>
/*每次点击加1*/
<button onClick={handleAdd}>加一</button>
</div>
)
}
В одном и том же событии он не будет вызываться дваждыsetCount
и разрешиcount
Увеличить в два раза, представьте, если в одном и том же событии каждый звонокsetCount
эффективны, то каждый вызовsetCount
Компонент будет перерисовываться один раз, что несомненно влияет на производительность, ведь если измененныйstate
такой же, последнийsetCount
новый в функцииstate
перезапишет предыдущий
useEffect && useLayoutEffect
- использовать
эти двоеhook
Использование такое же, первый параметр — функция обратного вызова, второй параметр — массив, а содержимое массива — зависимостьdeps
, функция обратного вызова выполняется после изменения зависимостей, обратите внимание, что компонент по умолчанию будет выполняться один раз при каждом его рендеринге.Если второй параметр не передан, пока компонентstate
Изменение вызовет функцию обратного вызова.Если передан пустой массив, он будет выполнен только один раз во время инициализации. Кроме того, если вы используетеreturn
Возвращает функцию, которая будет выполняться перед вызовом функции обратного вызова при каждом повторном рендеринге компонента.
- разница
На поверхности эти дваhook
Отличие в том, что время выполнения разное,useEffect
Функция обратного вызова будет выполнена после рендеринга страницы;useLayoutEffect
будет выполнен до того, как страница будет отображена. в действительностиReact
этим двумhook
обрабатываются по-разному,useEffect
является асинхронным вызовом, аuseLayoutEffect
является синхронным вызовом.
когда использоватьuseEffect
, когда использоватьuseLayoutEffect
Шерстяная ткань?
Я так понимаю, что это зависит от ситуации
Если функция обратного вызова изменитstate
вызывает повторный рендеринг компонента, что можетuseLayoutEffect
, потому что в это время используйтеuseEffect
Может вызвать мерцание страницы;
Если данные запрашиваются в функции обратного вызова или время выполнения js слишком велико, рекомендуется использоватьuseEffect
; потому что в это время используйтеuseLayoutEffect
Блокирует рендеринг браузера.
useMemo && useCallback
эти двоеhook
Может использоваться для оптимизации производительности и сокращения повторного рендеринга компонентов; теперь давайте взглянем на эти две магии.hook
как пользоваться.
- uesMemo
function MemoDemo() {
let [count, setCount] = useState(0);
let [render,setRender] = useState(false)
const handleAdd = () => {
setCount(count + 1);
};
const Childone = () => {
console.log("子组件一被重新渲染");
return <p>子组件一</p>;
};
const Childtwo = (props) => {
return (
<div>
<p>子组件二</p>
<p>count的值为:{props.count}</p>
</div>
);
};
const handleRender = ()=>{
setRender(true)
}
return (
<div style={{display:"flex",justifyContent:'center',alignItems:'center',height:'100vh',flexDirection:'column'}}>
{
useMemo(() => {
return <Childone />
}, [render])
}
<Childtwo count={count} />
<button onClick={handleAdd}>增加</button>
<br/>
<button onClick={handleRender} >子组件一渲染</button>
</div>
);
}
Childone
только компонентыrender
Изменения будут повторно отображены
Вот, кстати,React.memo
,использоватьReact.memo
Каждый раз, когда обернутый компонент отображается,props
будет и старыйprops
Выполняется поверхностное сравнение, и компонент не отображается, если нет изменений; пример выглядит следующим образом.
const Childone = React.memo((props) => {
console.log("子组件一被重新渲染",props);
return <p>子组件一{props.num}</p>;
})
function MemoDemo() {
let [count, setCount] = useState(0);
let [render,setRender] = useState(false)
let [num,setNum] = useState(2)
const handleAdd = () => {
setCount(count + 1);
};
const Childtwo = (props) => {
return (
<div>
<p>子组件二</p>
<p>count的值为:{props.count}</p>
</div>
);
};
const handleRender = ()=>{
setRender(true)
}
return (
<div style={{display:"flex",justifyContent:'center',alignItems:'center',height:'100vh',flexDirection:'column'}}>
{/* {
useMemo(() => {
return <Childone />
}, [render])
} */}
<Childone num={num}/>
<Childtwo count={count} />
<button onClick={handleAdd}>增加</button>
<br/>
<button onClick={handleRender} >子组件一渲染</button>
</div>
);
}
Этот пример является комбинацией предыдущего примераChildone
Выньте его и наденьтеReact.memo
В результате компонент не будет повторно визуализироваться после нажатия кнопки «Добавить», поскольку компонент не будет повторно визуализироваться.num
без изменений
- useCallback
По-прежнему в приведенном выше примере мы помещаемhandleRender
использоватьuseCallback
пакет, то есть здесьnum
Если изменений нет, каждый раз будет передаваться одна и та же функция, если она здесь не используетсяuseCallback
пакеты, каждый раз генерируются новыеhandleRender
, Привести кReact.memo
в функцииprops
После неглубокого сравнения было обнаружено, что для запуска рендеринга была сгенерирована новая функция.
const Childone = React.memo((props) => {
console.log("子组件一被重新渲染",props);
return <p>子组件一{props.num}</p>;
})
export default function MemoDemo() {
let [count, setCount] = useState(0);
let [render,setRender] = useState(false)
let [num,setNum] = useState(2)
const handleAdd = () => {
setCount(count + 1);
};
const Childtwo = (props) => {
return (
<div>
<p>子组件二</p>
<p>count的值为:{props.count}</p>
</div>
);
};
const handleRender = useCallback(()=>{
setRender(true)
},[num])
return (
<div style={{display:"flex",justifyContent:'center',alignItems:'center',height:'100vh',flexDirection:'column'}}>
{/* {
useMemo(() => {
return <Childone />
}, [render])
} */}
<Childone num={num} onClick={handleRender}/>
<Childtwo count={count} />
<button onClick={handleAdd}>增加</button>
<br/>
<button onClick={handleRender} >子组件一渲染</button>
</div>
);
}
useRef
этоhook
Обычно используется для получения экземпляров компонентов, а также может использоваться для кэширования данных❗
Чтобы получить экземпляр, не нужно слишком много объяснять.Следует отметить, что экземпляры есть только у компонентов класса;
СконцентрируйсяuseRef
Как кэшировать данные:
function UseRef() {
let [data, setData] = useState(0)
let initData = {
name: 'lisa',
age: '20'
}
let refData = useRef(initData) //refData声明后组件再次渲染不会再重新赋初始值
console.log(refData.current);
refData.current = { //修改refData后页面不会重新渲染
name: 'liyang ',
age: '18'
}
const reRender = () => {
setData(data + 1)
}
return (
<div>
<button onClick={reRender}>点击重新渲染组件</button>
</div>
)
}
После повторного рендеринга компонента переменная будет переназначена, вы можете использоватьuseRef
Кэшировать данные.После изменения этих данных компонент не будет перерисовываться.Если вы используетеuseState
Сохраните данные.После изменения данных компонент будет перерендерен, поэтому мы хотим сохранить данные по-тихому,useRef
Это лучший выбор 👊
Три нестандартных крючка
настроитьhook
, это,hook
упаковка, почему упаковкаhook
Шерстяная ткань?react
Официальный сайт дает ответ
Используйте один из крючковЦельИменно для решения проблемы функции жизненного цикла в классе часто содержат несвязанную логику, но связанная логика разделена на несколько разных методов. С помощью пользовательских хуков логика компонентов может быть извлечена в многократно используемые функции.
Давайте посмотрим на этот пример:
export default function CustomHook() {
let refone = useRef(null)
let X, Y, isMove = false,left,top
//基于鼠标事件实现拖拽
useEffect(() => {
const dom = refone.current
dom.onmousedown = function (e) {
isMove = true
X = e.clientX - dom.offsetLeft;
Y = e.clientY - dom.offsetTop;
}
dom.onmousemove = function (e) {
if (isMove) {
left = e.clientX - X
top = e.clientY - Y
dom.style.top = top + "px"
dom.style.left = left + "px"
}
}
dom.onmouseup = function (e) {
isMove = false
}
}, [])
return (
<div style={{ display: "flex", justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
<div ref={refone} style={{ width: '70px', height: '70px', backgroundColor: '#2C6CF9',position:'absolute' }}></div>
</div>
)
}
Мы просто используем события мыши, чтобы добиться эффекта перетаскивания квадрата, что, если этот эффект требуется и на других страницах? 😏 Итак, мы можем рассмотреть возможность инкапсуляции той же логики, как если бы мы извлекали общедоступные компоненты. Рассмотрим следующий пример:
import {useEffect, useRef } from "react";
function useDrop() {
let refone = useRef(null)
let X, Y, isMove = false,left,top
//基于鼠标事件实现拖拽
useEffect(() => {
const dom = refone.current
dom.onmousedown = function (e) {
isMove = true
X = e.clientX - dom.offsetLeft;
Y = e.clientY - dom.offsetTop;
}
dom.onmousemove = function (e) {
if (isMove) {
left = e.clientX - X
top = e.clientY - Y
dom.style.top = top + "px"
dom.style.left = left + "px"
}
}
dom.onmouseup = function (e) {
isMove = false
}
}, [])
return refone
}
export default function CustomHook() {
let refone = useDrop()
let reftwo = useDrop()
return (
<div style={{ display: "flex", justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
<div ref={refone} style={{ width: '70px', height: '70px', backgroundColor: '#2C6CF9',position:'absolute' }}></div>
<div ref={reftwo} style={{ width: '70px', height: '70px', backgroundColor: 'red',position:'absolute' }}></div>
</div>
)
}
Чтобы уменьшить объем кода, мы показываем только использование инкапсулированного кода на той же странице.hook
, на самом деле инкапсулирует этоhook
Разве не удивительно, что мы изменили всего несколько строк кода и реализовали повторное использование логики! 😆 Обратите внимание, чтоhook
Функция-оболочка должна начинаться сuse
в начале, потому что с помощьюhook
Существуют правила сами по себе, например, нельзя использовать в условных операторах.hook
, нельзя использовать вне функцииhook
; если не применимоuse
начать инкапсуляциюhook
,ноreact
Невозможно автоматически проверить использование этой функции.hook
соответствовать правилам.
Четыре резюме
Есть еще некоторые крючки, не упомянутые в этой статье, но не имеет значения, если вы изучите вышеизложенное и начнете другие крючки, вы сможете их понять Глубокое понимание, могу только сказать, что в следующий раз должно быть. .....