React:记账本07---自定义Hooks总结

291 阅读2分钟

项目中自定义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到[]不执行。