当前位置:   article > 正文

React实现keepAlive_react keep alive怎么用

react keep alive怎么用

keepAlive是什么

keep-alive是vue中的内置组件,使用keep-alive包裹组件可以在该组件的切换过程中将页面的状态缓存在内存中,界面切换后被包裹的组件实例不会被销毁,防止界面重复渲染DOM,并且可以防止在页面切换过程中组件的数据丢失

使用场景

如下图所示,想要实现以下效果:

1.第一步: 在user路由下的输入框中输入内容

在这里插入图片描述

2.第二步: 切换至home路由
在这里插入图片描述

3.第三步:再切换回来,保留上次输入的值
在这里插入图片描述

即:切换路由时缓存之前的组件,保留之前输入的值不被清空

vue项目可以使用内置的keep-alive组件包裹实现。react可以通过目前市面上的其他库来实现,例如React Activationreact-keep-alive等等,我们也可以手动实现。

代码实现

文件目录结构

核心功能实现在keepAlive目录中

/KeepAlive.js
包裹在需要缓存的组件外侧,通过Provider把状态和方法传递给子组件,如果判断出reactElement已经传过来了,但是对应的nodes数组还是为null的话就触发相应的reducer把该nodes重新赋值

import { useCallback, useReducer } from "react"
import {KeepAliveReducer} from './KeepAliveReducer'
import * as actionTypes from './types'
import { KeepAliveContext } from "./KeepAliveContext"

function KeepAlive(props) {
    console.log('KeepAlive props=>', props);
    /**
     * {
     *   home: {
     *      keepAliveId: 'home',
     *      reactElement: reactElement,
     *      nodes: nodes,
     *      status: create | created
     *   },
     *   user: {
     *      keepAliveId: 'user',
     *      reactElement: reactElement,
     *      nodes: nodes,
     *      status: create | created
     *   }
     * }
     */
    const [keepAliveStates, dispatch] = useReducer(KeepAliveReducer, {})
    
    const setKeepAliveState = useCallback(({ reactElement, keepAliveId }) => {
        if(!keepAliveStates[keepAliveId]) {
            dispatch({
                type: actionTypes.CREATING,
                payload: {
                    keepAliveId,
                    reactElement
                }
            })
        }
    }, [keepAliveStates])

    return (
        <KeepAliveContext.Provider value={{
            keepAliveStates,
            setKeepAliveState,
            dispatch
        }}>
        { props.children }
        {
            Object.values(keepAliveStates).map(({ keepAliveId, reactElement }) => (
                <div key={ keepAliveId } ref={(node) => {
                    console.log(keepAliveStates);
                    if(node && !keepAliveStates[keepAliveId].nodes) {
                        dispatch({
                            type: actionTypes.CREATED,
                            payload: {
                                keepAliveId,
                                nodes: [...node.childNodes]
                            }
                        })
                    }
                }}>{ reactElement }</div>
            ))
        }
        </KeepAliveContext.Provider>
    )
}

export default KeepAlive
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65

/keepAliveReducer.js

不同时机更新state的reducer

import * as actionTypes from './types'
/**
 * 
 * @param {*} state keepAliveStates
 * @param {*} action { type, payload }
 */
export function KeepAliveReducer(state, action) {
    const { type, payload } = action
    const { keepAliveId, reactElement, nodes } = payload

    switch(type) {
        case actionTypes.CREATING:
            console.log(state);
            return {
                ...state,
                [keepAliveId]: {
                    keepAliveId,
                    reactElement,
                    status: type,
                    nodes: null
                }
            }
        case actionTypes.CREATED:
            console.log(state);

            return {
                ...state,
                [keepAliveId]: {
                    ...state[keepAliveId],
                    status: type,
                    nodes
                }
            }
        default: return state
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

/keepAliveContext.js

自定义context

import { createContext } from 'react'

export const KeepAliveContext = createContext()
  • 1
  • 2
  • 3

/transfer.js

每次进入判断有无节点数组,没有则触发reducer把当前的组件赋值给state的
reactElement属性,如果有则通过appendChild方法把节点添加至当前组件下

/* eslint-disable react-hooks/rules-of-hooks */
import { useContext, useEffect, useRef } from "react"
import { KeepAliveContext } from "./keepAliveContext"


export function KeepAliveTransfer(KeepAliveComponent, keepAliveId) {

    return function(props) {
        const _ref = useRef(null) 
        const { keepAliveStates, setKeepAliveState } = useContext(KeepAliveContext)
        // console.log('keepAliveStates', keepAliveStates);
        // console.log('setKeepAliveState', setKeepAliveState);
        useEffect(() => {
            const state = keepAliveStates[keepAliveId]
    
            if(state && state.nodes) {
                console.log('有节点', state);
                state.nodes.forEach(node => _ref.current.appendChild(node))
            } else {
                console.log('无节点', state);
                setKeepAliveState({
                    reactElement: <KeepAliveComponent { ...props }/>,
                    keepAliveId
                })
            }
        }, [keepAliveStates, setKeepAliveState, props])
        return (
            <div ref={ _ref }></div>
        )
    }
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

/types.js

export const CREATING = 'CREATING'
export const CREATED = 'CREATED'
  • 1
  • 2

源码自取-https://gitee.com/mountain-casserole/react-keep-alive

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/119129
推荐阅读
相关标签
  

闽ICP备14008679号