React旺財記帳-數據持久化與數據展現

更優雅的更新與刪除

更新

不優雅版

const updateTag = (id: number, obj: { name: string }) => {
    //獲取要修改的tag的下標
    const index = findTagIndex(id);
    //深拷貝tags
    //vue能夠直接在原數據上修改,但react不支持這項功能,由於它認爲數據不可變
    const tagsClone = JSON.parse(JSON.stringify(tags))
    //把tagsClone的第index個刪掉,換成{id: id, name: obj.name}
    tagsClone.splice(index, 1, {id: id, name: obj.name})
    setTags(tagsClone)
}
複製代碼

優雅版

const updateTag = (id: number, obj: { name: string }) => {
    setTags(tags.map(tag => tag.id === id ? {id, name: obj.name} : tag));
}
複製代碼

刪除

不優雅版

const deleteTag = (id: number) => {
    //獲取要刪除的tag的下標
    const index = findTagIndex(id);
    //深拷貝tags
    //vue能夠直接在原數據上修改,但react不支持這項功能,由於它認爲數據不可變
    const tagsClone = JSON.parse(JSON.stringify(tags))
    //把tagsClone的第index個刪掉
    tagsClone.splice(index, 1)
    setTags(tagsClone)
}
複製代碼

優雅版

const deleteTag = (id: number) => {
    setTags(tags.filter(tag => tag.id !== id))
}
複製代碼

增長編輯頁面回退功能

爲了使icon能夠點擊,須要修改Icon組件,即自定義Icon須要繼承SVG全部屬性vue

問題在於,當使用 ...rest時,若是rest裏擁有className那就會覆蓋本來的className,爲了解決這個問題,須要添加組件react

yarn add classnames
yarn add --dev @types/classnames
複製代碼

注意:保持版本號一致markdown

更新後的Icon代碼:svg

import React from 'react';
import cs from 'classnames';

let importAll = (requireContext: __WebpackModuleApi.RequireContext) => requireContext.keys().forEach(requireContext);
try {importAll(require.context('icons', true, /\.svg$/));} catch (error) {console.log(error);}

type Props = {
  name?: string
} & React.SVGAttributes<SVGElement>

const Icon = (props: Props) => {
  const {name, children, className, ...rest} = props
  return (
    <svg className={cs('icon', className)} {...rest}>
      {props.name && <use xlinkHref={'#' + props.name}/>}
    </svg>
  );
};

export default Icon;
複製代碼

解決createId刷新後id重置問題

解決方法是記住最後一次的id值,下次直接從 localStorage 中讀取ui

let id = parseInt(window.localStorage.getItem('idMax') || '0')
const createId = () => {
    id += 1;
    window.localStorage.setItem('idMax', id.toString())
    return id;
}

export {createId}
複製代碼

解決標籤持久化問題

自定義useUpdate

頁面第一次默認刷新後,當deps改變時進行fn()spa

import {useEffect, useRef} from "react";

const useUpdate = (fn: () => void, deps: any[]) => {
    const count = useRef(0)
    useEffect(() => {
        count.current += 1;
    })
    useEffect(() => {
        if (count.current > 1) {
            fn()
        }
    }, deps);//這裏必須是不可變數據
}
export {useUpdate}
複製代碼

讀取localStorage並新增

注意默認標籤的使用方法,即當localStorage爲空時設定默認標籤rest

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)
}, [])
useUpdate(() => {
    window.localStorage.setItem('tags', JSON.stringify(tags))
}, [tags])//組件掛載時執行
複製代碼

解決記帳頁面持久化問題

以前沒有寫點擊ok後會發生什麼,如今進行補充。在點擊ok後,數據應該被存入localStorage中,即進行submit操做code

const submit = () => {
    addRecord(selected)
    alert('保存成功')
    setSelected(defaultFormdata)
}
複製代碼

其中addRecord是自定義hook中的功能orm

import {useEffect, useState} from "react";
import {useUpdate} from "./useUpdate";

type newRecordItem = {
    tagIds: number[]
    note: string
    category: '+' | '-'
    amount: number
}

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) => {
        const record = {...newRecord, createdAt: (new Date()).toISOString()}
        setRecords([...records, record])
    }
    return {records, addRecord,}
}

export {useRecords}
複製代碼

小技巧:若是兩種類型很像,想不重複代碼,第一種方法是上面代碼使用的 & 技巧,還能夠把多的類型中的某幾個刪除,代碼爲type newRecordItem = Omit<RecordItem, 'createdAt' | 'updatedAt'>繼承

相關文章
相關標籤/搜索