前言
之前不是准备在学习 react
就是在学习 react
的路上,但都是在学了一段时间就因其他事情搁置了,也没有做相应的学习笔记,导致后面再用,还需要看 api
,而且之前做的项目也都是用的比较基础的东西,所以在面试时并没有自信能够说出自己有丰富的 react
开发经验。所以现在一边复习之前学习的东西,一边对之前的系统进行 react
重构,做一个深入的了解和使用。
Hooks API
useState
useState
等同于 vue3
中 reactive
或者 ref
方法,来生成响应式数据。不过 useState
会多创建一个修改该响应式数据的方法
const [count, setCount] = useState(1);
const updateCount = () => {
setCount((pre: number) => pre + 1);
// setCount 为异步更新,此时 count 还是之前的数据,我们可以通过 useEffect 来获取更新后的数据
};
useEffect
useEffect
类似于 vue3
中的 watch
和 computed
, 可以监测到数据的变化。同时也可以作为生命周期函数使用。
1 当作为生命周期来使用时,可以对 useEffect
第二个参数以空数组监测
useEffect(() => {
console.log('作为生命周期函数执行');
}, []);
2 第二个参数不传,监测所有的变化
useEffect(() => {
console.log('作为生命周期函数执行');
});
3 对部分数据做监测,将监测数据加入数组即可
const [count, setCount] = useState(1);
const updateCount = () => {
setCount((pre: number) => pre + 1);
};
useEffect(() => {
console.log('作为生命周期函数执行');
}, [count]);
4 返回值 useEffect 的第一个入参,最终返回 destory
,它会在下一次 callback 执行之前调用,其作用是清除上次的 callback 产生的副作用,比如清除计时器等
useEffect(() => {
return () => {
clearInterval(timer); // timer 为我们定义的计时器
timer = null;
};
}, [xxx]);
useContext
类似于 vue
中 provide
inject
通过在上层组件中传值,在子孙后代中使用。
通过 createContext
进行创建,在父组件中通过 Provider
进行数据提供,在子孙组件中使用 useContext
进行数据获取
// useContext
import { useContext, createContext, useState } from 'react';
const CountContext = createContext(-1);
function User() {
const [count, setCount] = useState(1);
const changeCount = () => {
setCount(pre => pre + 1);
};
return (
<div>
<div>父组件count={count}</div>
<button onClick={changeCount}>修改值</button>
<CountContext.Provider value={count}>
<UserChild />
</CountContext.Provider>
{/* .Provider 提供数据 */}
</div>
);
}
export default User;
const UserChild = () => {
const count = useContext(CountContext);
//接收数据
return (
<div>
子组件展示count={count}
{/* 展示数据 */}
<Son></Son>
</div>
);
};
const Son = () => {
const count = useContext(CountContext);
return <div style={{ marginTop: 10 }}>孙组件获取到的count: {count}</div>;
};
// rsf
useImperativeHandle
useImperativeHandle
用于将子组件的方法暴露给父组件使用,等同于vue3 中 defineExpose。
使用方法:在父组件中对子组件进行 ref
绑定,在子组件中通过 useImperativeHandle
将子组件的 addChild
方法暴露出来,父组件通过 childrenRef.current.addChild
进行使用
// useReducer
import { useRef, forwardRef, useImperativeHandle } from 'react';
//父组件调用子组件方法
const Children = forwardRef((props: any, ref: any) => {
const addChild = () => {
console.log('父组件调用子组件 addChild 方法');
};
useImperativeHandle(ref, () => ({
addChild,
}));
return (
<div ref={ref}>
<div>我是子组件</div>
</div>
);
});
function User() {
const childrenRef: any = useRef(null);
const handleChildren = () => {
if (childrenRef.current.addChild) {
childrenRef.current.addChild();
}
};
return (
<div>
<div>User</div>
<button onClick={handleChildren}>调用子组件方法</button>
<Children ref={childrenRef}></Children>
</div>
);
}
export default User;
useMemo
缓存机制,在react 中父组件更新,会导致子组件重新渲染,为了节约性能,我们可以将改变的部分也提炼出来作为一个子组件,或者也可以通过useMemo进行组件缓存。
import { useMemo, useState } from 'react';
const usePow = (list: number[]) => {
return useMemo(
() =>
list.map((item: number) => {
return <div key={item}>{item}</div>;
}),
[]
);
};
function User() {
const [flag, setFlag] = useState(false);
const [powData, setPowData] = useState([1, 2, 3]);
const setList = () => {
setPowData([1, 2, 3]);
};
return (
<div>
<div>user</div>
<div>数字集合:{usePow(powData)}</div>
<br />
<button onClick={() => setList()}>数组数据</button>
状态{flag ? '真' : '假'}
<br />
<button onClick={() => setFlag(!flag)}>修改状态</button>
</div>
);
}
export default User;
//问题点,遍历的数组数据不能使用 useState 方式修改,如果将 usePow 函数放入 User 函数体内,数据每次渲染 usePow 会重新执行,也就失去了Memo的作用
// rsf
useReducer
简单来说,就是整合方法,使用方法和redux 类似,通过 type 进行相应的操作。但个人感觉有点多此一举,还不如直接通过传参方式来调用对应的方法。
// useReducer
import { useReducer } from 'react';
function User() {
const [count, dispatch] = useReducer((state: number, action: any) => {
switch (action?.type) {
case 'add':
return state + action?.payload;
case 'sub':
return state - action?.payload;
default:
return state;
}
}, 0);
const changeCount = (type: number) => {
if (type === 1) {
dispatch({ type: 'add', payload: 11 });
} else {
dispatch({ type: 'sub', payload: 1 });
}
};
return (
<div>
<div>user</div>
<div>{count}</div>
<br />
<button onClick={() => changeCount(1)}>增加值</button>
<br />
<br />
<button onClick={() => changeCount(2)}>减少值</button>
</div>
);
}
export default User;
结语
明显看的出来这篇有点敷衍了事了,先完成 kpi 吧,等下个月再进行更新补充,此时2023年7月31号21点45,还有一篇文章未完成,就如考试就剩十五分钟了,作文还没写。加把劲,凌晨前结束下一篇