项目中自定义Hooks
有三个hooks:
- useTags
- useUpdate
- useRecords
1. useTags
- 主要是对tags进行处理的逻辑
import {useEffect, useState} from "react";
import {createId} from "lib/createId";
import {useUpdate} from "./useUpdate";
const useTags = ()=> {
const [tags,setTags] = useState<{id:number;name:string}[]>([]);
useEffect(()=>{
//console.log('after mount')
let localTags = JSON.parse(window.localStorage.getItem('tags') || '[]')
// 如果长度为0,就是空,push预设值
if(localTags.length ===0){
localTags = [
{id:createId(), name:'衣'},
{id:createId(), name:'食'},
{id:createId(), name:'住'},
{id:createId(), name:'行'}
]
}
setTags(localTags)
},[])// 组件挂载时执行
useUpdate(()=>{
console.log('set')
window.localStorage.setItem('tags',JSON.stringify(tags))
},tags)
const findTag = (id:number) =>tags.filter(tag=>tag.id === id)[0]
const findTagIndex = (id:number)=>{
let result = -1;
for(let i =0;i<tags.length;i++){
if(tags[i].id === id){
result = i;
break;
}
}
return result
};
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}])
}
};
const getName=(id:number)=>{ //根据id找tagName
const tag = tags.filter(t=>t.id === id)[0]
return tag ? tag.name : ''
}
return {
tags:tags,
setTags:setTags,
findTag:findTag,
updateTag:updateTag,
deleteTag:deleteTag,
addTag:addTag,
getName:getName
}
}
export default useTags;
// tag : string=> tag: {id:number,name:string}
useState
使用useState初始化tags,产生setTags
const [tags,setTags] = useState<{id:number;name:string}[]>([]);
useEffect
- 第一次挂载时执行
- 读取本地localStorage是否有tags,有就调用,没有就push
// 组件挂载时执行,只有第一次执行
useEffect(()=>{
//console.log('after mount')
let localTags = JSON.parse(window.localStorage.getItem('tags') || '[]')
// 如果长度为0,就是空,push预设值
if(localTags.length ===0){
localTags = [
{id:createId(), name:'衣'},
{id:createId(), name:'食'},
{id:createId(), name:'住'},
{id:createId(), name:'行'}
]
}
setTags(localTags)
},[])
useUpdate
- 用来更新localStorage里用来持久化的数据,详见useUpdate hook
useUpdate(()=>{
console.log('set')
window.localStorage.setItem('tags',JSON.stringify(tags))
},tags)
findTag
- 根据id,查询标签
const findTag = (id:number) =>tags.filter(tag=>tag.id === id)[0]
updateTag
- 编辑标签
- 输入id和新的name,使用setState触发更新
const updateTag =(id:number,obj:{name:string})=>{
setTags(tags.map(tag=>tag.id === id? {id,name:obj.name} :tag))
};
deleteTag
- 删除标签
- 用setState将id的tag移除
const deleteTag=(id:number)=>{
setTags(tags.filter(tag=>tag.id !== id))
}
addTag
- 新增标签
- 标签名自己输入,id使用creatId()计算
const addTag=()=>{
const tagName = window.prompt('新标签的名称为');
if(tagName !== null && tagName !== ''){
setTags([...tags,{id:createId(),name:tagName}])
}
};
getName
- 根据id查找标签名称
const getName=(id:number)=>{ //根据id找tagName
const tag = tags.filter(t=>t.id === id)[0]
return tag ? tag.name : ''
}
2. useUpdate
- 主要用来更新locaolStorage里的数据
import {useEffect, useRef} from "react";
const useUpdate=(fn:()=>void,dependency:any[])=> {
const count = useRef(0)
useEffect(() => {
count.current += 1;
})
useEffect(() => {
if (count.current > 1) {
fn()
}
}, [fn,dependency]) //tags必须是不可变值,每次修改是一个新的对象,在【tags】变化的时候执行
}
export {useUpdate}
- 使用useRef创建一个不随渲染改变的值】
- 每次调用执行加1
- ref大于1的时候执行fn(),因为第一次不需要执行
3. useRecords
- 主要用于处理records
import {useEffect, useState} from "react";
import {useUpdate} from "./useUpdate";
type newRecordItem = {
tagIds:number[],
note:string,
category:"+" | '-',
amount:number,
}
export type RecordItem = newRecordItem & {
createdAt:string //ISO 8601
}
const useRecords =()=>{
const [records,setRecords] = useState<RecordItem[]>([])
useEffect(()=>{
setRecords(JSON.parse(window.localStorage.getItem('records')||'[]'))
},[])//挂载时获取
useUpdate(()=>{
window.localStorage.setItem('records',JSON.stringify(records))
},records)
const addRecord=(newRecord:newRecordItem)=>{
if(newRecord.amount <=0){
alert('请输入正确金额 ')
return false
}
if(newRecord.tagIds.length === 0){
alert('请选择标签')
return false
}
const record = {...newRecord,createdAt:(new Date()).toISOString()}
setRecords([...records,record])
return true
}
return {records, addRecord}
}
export {useRecords}
addRecord
- 新增记录
- 新增的记录如果满足要求,就setRecord,重新渲染。
const addRecord=(newRecord:newRecordItem)=>{
if(newRecord.amount <=0){
alert('请输入正确金额 ')
return false
}
if(newRecord.tagIds.length === 0){
alert('请选择标签')
return false
}
const record = {...newRecord,createdAt:(new Date()).toISOString()}
setRecords([...records,record])
return true
}
useEffect+useUpdate
- useEffect: 第一次挂载执行,读取localStorage中的record或设置[]
- useUpdate: 当addRecord触发record变化时执行。
- record从undefined到[]不执行
useEffect(()=>{
setRecords(JSON.parse(window.localStorage.getItem('records')||'[]'))
},[])//挂载时获取
useUpdate(()=>{
window.localStorage.setItem('records',JSON.stringify(records))
},records)
4. useRecord和useTags中useEffect+useUpdate
- 两个是一样的
- useEffect: 第一次挂载执行,读取localStorage中的record/tags或设置[]
- useUpdate: 当触发record/tags变化时执行。
- 第一次:ref=1时,record/tags从undefined到[]不执行。