最近在学习React,并使用 React + TypeScript 实现了一个记账应用。在本文中会总结一些 React Hooks 入门的技巧。
useState
useState 可以返回两个数据,第一个数据为初始变量,第二个数据为修改变量的方法。然后再传入一个初始值,即可完成一个 useState。
比如我定义一个变量 tags,同时也需要定义一个 setTags ,方便后续对 tags 进行修改。这里的初始值是 [],一个空数组。useState 结合TS语法,需要在后面加上 <> 声明数据类型,即以下代码中的 { id: number, name: string }[]。
const [tags, setTags] = useState<{ id: number, name: string }[]>([]);
//把 tags 和 setTags 暴露出去
return {tags, setTags};
复制代码
我们还可以使用 return 析构语法把 tags 和 setTags 暴露到外部,方便其他组件使用。项目中,需要写一个根据标签ID来确定标签的功能,就使用到了 useState 中的 tags。
const findTag = (id: number) => tags.filter(tag => tag.id === id)[0];
复制代码
在制作“添加标签”功能时,使用到了 setTags 来更改 tags 的值:
const addTag = () => {
const tagName = window.prompt('请输入标签名');
if (tagName !== null && tagName !== '') {
setTags([...tags, {id: createId(), name: tagName}]);
}
};
复制代码
useState 中的两个返回值,也可以结合到 useEffect 中使用:
useEffect(() => {
let localTags = JSON.parse(window.localStorage.getItem('tags') || '[]');
if (localTags.length === 0) {
localTags = [
{id: createId(), name: '衣服'},
{id: createId(), name: '食物'},
{id: createId(), name: '住房'},
{id: createId(), name: '交通'}
];
}
setTags(localTags)
}, []);
复制代码
在这个 useEffect 中,依赖值留空,可以实现在进入页面后马上渲染出数据。以上代码首先在 LocalStorage 中对标签数据进行读取,判断标签数据是否存在,如存在则在渲染UI后使用 setTags 写入数据。
useReducer
useReducer 可以理解成 useState 的高级版。
使用步骤主要为以下4步:
第一步:创建一个初始值 initialState
const initial = {
n: 0
};
复制代码
第二步:创建对数据的所有操作,以下代码可以对数字实现 +1 和 *2 功能:
const reducer = (state, action) => {
if (action.type === "add") {
return { n: state.n + action.number };
} else if (action.type === "multi") {
return { n: state.n * 2 };
} else {
throw new Error("unknown type");
}
};
复制代码
第三步:将创建的 reducer 传给 useReducer 得到读写API,useReducer 接受两个参数,一个是 reducer,一个是 initial。返回两个参数,一个是 state 保存值,另一个是 dispatch。以下代码中 state 的 n 就是上面 initial 的 n。
const [state, dispatch] = useReducer(reducer, initial);
const { n } = state;
复制代码
使用 dispatch 来调用之前写好的 add,数字即可+1,跟 useState 中的 setX 一样的效果。此时的 onClick 方法非常简单,对数据的操作都被集成到 reducer 中,onClick 只触发 dispatch,然后调用相应的 reducer 即可。
const onClick = () => {
dispatch({ type: "add", number: 1 });
};
const onClick2 = () => {
dispatch({ type: "multi", number: 2 });
};
复制代码
useEffect
在 React 的官方文档中,useEffect 可以理解成 componentDidMount、componentDidUpdate和componentWiilUnmount 的结合体。useEffect 接收一个函数,这个函数会在组件渲染之后才执行,返回的方式有两种。要么返回一个能清除副作用的函数,要么不返回任何内容。
一般的用法如下:
useEffect(() => {
// 函数
}, [//更新依赖]);
复制代码
useEffect 接受两个参数。第一个是函数,放入异步操作的代码。第二个参数是依赖项数组,只要数组有变化,useEffect 就会执行。
useEffect(() => {
if (count.current > 1) {
fn();
}
}, [fn, dependency]);
复制代码
上面代码中,只要 fn 或 dependency 发生变化,useEffect 就会执行。组件在第一次渲染时,useEffect 也会执行,如果渲染后依赖项发生变化,就会执行两次。
useContext
如果需要组件之间共享状态,可以使用 useContext。一般用于同级之间的组件通信。
使用 useContext 只需3步:
首先使用 React.createContext() 创建一个 context:
const Context1 = React.createContext(null)
复制代码
使用 <Context1.Provider> 圈定作用域:
function App() {
const [n, setN] = useState(0)
return (
<Context1.Provider value={{n,setN}}>
<div className="App">
<Dad/>
</div>
</Context1.Provider>
);
}
复制代码
作用域内使用 useContext(Context1) 来使用上下文:
function Dad(){
return(
<div>
我是爸爸
<Child/>
</div>
)
}
function Child() {
const { n, setN } = useContext(C);
const onClick=()=>{
setN(i=>i+1)
}
return(
<div>我是儿子 我得到的n: {n}
<button onClick={onClick}>+1</button>
</div>
)
}
复制代码
封装自定义 hook
记账软件需要对用户输入的标签进行增、删、改、查等操作,可以把这些操作都封装到一个 useTags 组件中,方便共享。
const useTags = () => {
const [tags, setTags] = useState<{ id: number, name: string }[]>([]);
const findTag = (id: number) => tags.filter(tag => tag.id === id)[0];
const updateTag = (id: number, obj: { name: string }) => {
setTags(tags.map(tag => tag.id === id ? {id, name: obj.name} : tag));
};
const deleteTag = (id: number) => {
setTags(tags.filter(tag => tag.id !== id));
};
const addTag = () => {
const tagName = window.prompt('请输入标签名');
if (tagName !== null && tagName !== '') {
setTags([...tags, {id: createId(), name: tagName}]);
}
};
return {tags, setTags, findTag, updateTag, deleteTag, addTag};
};
export {useTags};
复制代码
其他组件就可以使用 useTags 中的一些方法:
const TagsSection: React.FC<Props> = (props) => {
// 从useTags中提取出tag和addtag
const {tags, addTag} = useTags();
const selectedTagIds = props.value;
......
return (
<Wrapper>
<button onClick={addTag}>新增标签</button>
</Wrapper>
);
};
复制代码






















![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)