React项目中使用自定义Hook
+useContext
进行状态管理。
自定义Hook
自定义Hook
必须是以use开头的函数,否在React
语法检查不会让你过。由于React
的useState
在函数执行时会被顺序存储在链表中,所以自定义Hook
只能在函数的第一层调用。不能放在条件判断中,因为判断条件会影响useState
的执行顺序,导致存储进链表的顺序受到影响。
代码示例
使用自定义Hook对record的一系列操作封装为一个自定义Hook
函数。数据存储在useState
中。并暴露出操作状态的一系列方法。就可做到类似Vue
中multiple
功能
//定义record类型
export type RecordItem={
id:number
tagId:number
note:string
createdAt:string
}
//定义useRecord返回的类型
export type RecordAction = {
records:RecordItem[]
createRecord:(record: RecordItem)=>void
deleteRecord:(id: number)=>void
updateRecord:(id: number, record: RecordItem)=>void
findRecord:(id: number)=>void
}
const useRecords = (): RecordAction => {
const [records, setRecords] = useState<RecordItem[]>(recordList);
//增
const createRecord = (record: RecordItem) => {
if (!record.createAt)
//使用dayjs格式化记录创建时间时间
record.createAt = dayjs(new Date()).format('YYYY-MM-DDTHH:mm:ss');
record.id = createId(); //生成ID
setRecords((rs) => [...rs, record]);
};
//删
const deleteRecord = (id: number) => {
setRecords((rs) => rs.filter((r) => r.id !== id));
};
//改
const updateRecord = (id: number, record: RecordItem) => {
setRecords((rs) => rs.map(r => r.id === id ? {id, ...record} : r));
};
//查
const findRecord = (id: number) => {
return records.filter((r) => r.id === id)[0];
};
return {
createRecord,
deleteRecord,
updateRecord,
findRecord,
records
}
}
export default useRecords
这样就可以在项目中使用useRecord来对记录的状态进行管理。
注意你需要保证整个项目useReacord只调用了一次,毕竟它只是一个函数,每次调用都会创建新的state,如果在不同的组件中多次调用这会导致数据不同步。
那么如何做到只调用一次useRecord呢,可以使用useContext在最上顶成组件中将useRecord()执行后返回的对象(操作records的方法)传递到子组件中即可。
context.tsx
import {createContext} from 'React'
import {RecordAction} from 'hooks/useRecord' //createContext接受的类型
const ContextReacrd = createContext<RecordAction>({})
export default ContextRecord
App.tsx
import React from 'react'
import ContextRecord from '/../ContextRecord'
import useRecord from 'hooks/useRecord'
const App = ()=>{
const recordAction = useRecord() //返回操作record的方法
return(
<ContextRecord.Provider value={recordAction}>
<Child />
</ContextRecord.Provider>
)
}
这样在后代组件中就可以使用useContext来拿到操作state的函数。
Child.tsx
import React,{useContext} from 'react'
import ContextRecord from '/../ContextRecord'
const Child = ()=>{
const recordAction = useContext(ContextRecord)//拿到操作record的函数
return (
<Child2 />
)
}
export default Child