Data persistence

  1. Why do data persistence?
  • Because it is not persistent, the data is stored in memory and is lost when refreshed
  • In this way, the data of different pages can be unified throughout the project
  1. How to do?
  • Use custom Hooks in conjunction with Localstorage

Persistent TAB data

1. Encapsulate addTag into useTag

    const addTag=() = >{
        const tagName = window.prompt('The name of the new label is');
        if(tagName ! = =null&& tagName ! = =' '){
            setTags([...tags,{id:createId(),name:tagName}])
        }
    };
Copy the code

2. When to put tags into localStorage? UseEffect to help you out

  1. Whenever the tags change, they are put into localStorage
  • LocalStoarge can only store strings, so useJSON.stringify
    • Use a dependency for[tags]The useEffect
        useEffect(() = >{
            console.log('tags change')
            console.log(tags)
            window.localStorage.setItem('tags'.JSON.stringify(tags))
        },[tags]) // Execute when dependency changes
    Copy the code
  • Add a useEffect to make the dependency[]
    • []: executes when the component is mounted, executes only once on mount, and then no longer executes
     useEffect(() = >{
            console.log('after mount')
            let localTags = JSON.parse(window.localStorage.getItem('tags') | |'[]')
            setTags(localTags)
        },[])// When the component is mounted, it is executed only once on mount and then no longer executed
    Copy the code
  • What happens if you add a tag to two useeffects together?
    • Print after mount first: depends on the useE of []
    • Print tags change: useEffect dependent on [tags]
    • Print [] : tags from un______ to []
    • Print tags change: useEffect dependent on [tags]
    • Print the newly added tags object: [] becomes the new object
  • The first print [] is redundant, and the first print [] is not needed.
    • Declare a ref, each time useEffect increments by 1,
    • Equal to 1 means first render, first render does nothing.
    • UseEffect is executed only when ref is greater than 1
    • Encapsulate as a hook, useUpdate. I’m done with that extra set
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 must be immutable. Each change is a new object, executed when tags change
}
export {useUpdate}

Copy the code
  • So the useTags became
   // Execute mount once and then no longer
    useEffect(() = >{
        let localTags = JSON.parse(window.localStorage.getItem('tags') | |'[]')
        // If the length is 0, it is null, push default
        if(localTags.length ===0){
            localTags = [
                {id:createId(), name:'clothes'},
                {id:createId(), name:'food'},
                {id:createId(), name:'live'},
                {id:createId(), name:'row'}}]// Read localStoarge tags, then setTags
        setTags(localTags)
    },[])// When the component is mounted, it is executed only once on mount and then no longer executed
    // Execute this when updating
    useUpdate(() = >{
       // console.log('set')
        window.localStorage.setItem('tags'.JSON.stringify(tags))
    },tags)
Copy the code

3. Note tags. TSX execution times

  • Enter the TAB pagetags do itIt will execute it twice, the first time tags fromundeinedto[]And the second[]To the initialization value
function Tags() {
   const {tags,addTag} = useTags()
    console.log('tags do it')
    return (
        <Layout>
            <TagList>
                {tags.map(tag=>
                    <li key={tag.id}>
                        <Link to={'/tags/ '+tag.id} >
                            <span className="oneLine">{tag.name}</span>
                            <Icon name="right"></Icon>
                        </Link>

                    </li>
                )}
            </TagList>
            <Center>
                <Space/>
            <Button onClick={addTag}>The new labels</Button>
                <Space/>
            </Center>
        </Layout>

    );
}
Copy the code

4. Process sorting

  • Enter the TAB pagetags do itIt will execute it twice, the first time tags fromundeinedto[]And the second[]To the initialization value
  • Each time you switch pages, the component is remounted, i.euseTagsIn theuseEffectIt takes effect and sets the initial value
    • Go to thelocalStoragE, if it’s empty, push the initial value
  • If thetagsUpdate, and it will triggeruseUpdate
    • Coexist inlocalStorage
    • Only if the set ref is greater than 1 (i.e. from [] to tags)localStorage

Persistent billing page data

1. Create userecord.tsx hooks

  • AddRecord exposure records
import {useEffect, useState} from "react";
import {useUpdate} from "./useUpdate";

// The type of new record
type newRecordItem = {
    tagIds:number[].note:string.category:"+" | The '-'.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') | |'[]'))
    },[])// Mount
    useUpdate(() = >{
        window.localStorage.setItem('records'.JSON.stringify(records))
    },records)
    const addRecord=(newRecord:newRecordItem) = >{
        if(newRecord.amount <=0){
            alert('Please enter the correct amount')
            return false
        }
        if(newRecord.tagIds.length === 0){
            alert('Please select label')
            return false
        }
        constrecord = {... newRecord,createdAt: (new Date()).toISOString()}
        setRecords([...records,record])
        return true
    }
    return {records, addRecord}
}
export {useRecords}

Copy the code

2. Click OK on the bookkeeping page to submit the record

   const submit=() = >{
       if(addRecord(selected)) {
           alert('Saved successfully')
           setSelected(defaultFormData)
       }

    }
Copy the code
<NumberpageSection value={selected.amount}
                onChange={(amount) = >onChange({amount})}
                    onOk={submit}
/>
Copy the code

3. Logic for adding records

  • On the first rendering, mount the componentlocalStorageIn the readingrecords
  • In the Money component, enter the record and click OK to calladdRecord
  • inuseRecordIn the hook,addRecordIn the wouldsetRecordsTo updaterecord, trigger the update
  • Let the Money component execute again, and the Money component can get a new onerecordsthe
  • At the same time,useRecordsIn the calluseUpdate, rely onrecordsWhen the record changes, update the new records tolocalStorage