tags页面数据持久化
使用useEffect获取和存储tags到localstorage
const useTags = () => {const [tags, setTags] = useState<{id: number, name: string}[]>([])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(()=>{window.localStorage.setItem('tags', JSON.stringify(tags))},[tags])// ...}
注意,这样写会导致setItem执行2次,一次是tags从undefined变成[], 第二次是tags从[]变成['衣','食','住','行']
使用count计算渲染的次数,让第一次渲染时不执行setItem
注意:当你希望一个变量在组件不断render时保持不变,使用useRef
let count = useRef(0)useEffect(()=>{count.current += 1})useEffect(()=>{if(count.current > 1) {window.localStorage.setItem('tags', JSON.stringify(tags))}},[tags])
封装成useUpdate hooks
import {useEffect, useRef} from 'react';export const useUpdate = (fn: ()=>void, deps: any[]) => {const count = useRef(0)useEffect(()=>{count.current += 1})useEffect(()=>{if(count.current > 1) {fn()}},deps)}
修改createId
let id = parseInt(window.localStorage.getItem('idMax') || '0')const createId = () => {id += 1;window.localStorage.setItem('idMax', id.toString())return id;}export {createId}
useEffect的执行时机
每个使用useTags的组件,在刷新时都会重新渲染,重新获取tags的状态useEffect(()=>{//do something}, [])是在componentDidMount周期运行的
useState在Mount前运行,此时tags为空数组,所以在tags组件中要判断tag是否为空
const Tag: React.FC = () => {const history = useHistory();const {findTag, updateTag, deleteTag} = useTags();const {id} = useParams<Params>();const tag = findTag(parseInt(id));const tagContent = (tag:{id: number, name: string}) => (<><InputWrapper><Input label="标签名"type="text"placeholder="标签名"value={tag.name}onChange={(e) => updateTag(tag.id, e.target.value)}/></InputWrapper><Center><Space/><Space/><Space/><Button onClick={() => {const result = deleteTag(tag.id);if(result === 'success')history.goBack();}}>删除标签</Button></Center></>)return (<Layout><TopBar><Icon name="left" onClick={()=> history.goBack()}/><span>编辑标签</span><Icon/></TopBar>{tag ? tagContent(tag) : ''}</Layout>);};
Money页面数据持久化
useRecords
import {useEffect, useState} from 'react';import {useUpdate} from './useUpdate';type RecordItem = {tagIds: number[],category: '-' | '+',note: string,amount: number,createAt: string}type newRecordItem = Omit<RecordItem, 'createAt'>export const useRecords = () => {const [records, setRecords] = useState<newRecordItem[]>([])useEffect(()=>{setRecords(JSON.parse(window.localStorage.getItem('records') || '[]'))}, [])const addRecord = (record: newRecordItem) => {if(record.amount <= 0) {alert('请输入金额')return false}if(record.tagIds.length === 0) {alert('请选择标签')return false}const newRecord:RecordItem = {...record, createAt: new Date().toISOString()}setRecords([...records, newRecord])return true}useUpdate(()=>{window.localStorage.setItem('records', JSON.stringify(records))}, [records])return {records,addRecord,}}
