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,
}
}