shenjunru / react-fiber-keep-alive

A component that maintains component state and avoids repeated re-rendering.
MIT License
60 stars 1 forks source link

如何设置最大缓存数量 #1

Closed Leecason closed 1 year ago

Leecason commented 2 years ago

https://github.com/StructureBuilder/react-keep-alive/ 有 max 属性设置最大缓存数量,在超出最大值之后就会删除缓存中的值

shenjunru commented 2 years ago

目前没有cache数量控制的功能。 只有 <KeepAlive ignore> 或者 useIgnoreKeepAlive() 用来消除 cache。 也可以自己实现计数功能。 欢迎提PR

Leecason commented 2 years ago

如果我想基于已有的 API 来实现最大缓存数量是 5,可以怎么写呢

shenjunru commented 2 years ago
import * as React from 'react';
import { keepAlive, useIgnoreKeepAlive } from 'react-fiber-keep-alive';

const KeepAliveControllerContext = React.createContext<null | ((name: string) => void)>(null);

export const KeepAliveController: React.FC<{
    max: number;
    children?: React.ReactNode;
}> = ({ max, children }) => {
    const size = React.useRef(max);
    size.current = max;

    const [fifo, setFIFO] = React.useState<string[]>([]);
    const clear = useIgnoreKeepAlive();

    const push = React.useCallback((name: string) => setFIFO((list) => {
        const rest = list.filter((e) => e !== name);
        return [...rest, name];
    }), []);

    React.useEffect(() => {
        if (Number.isFinite(max) && 0 < max) {
            fifo.slice(0, Math.max(0, fifo.length - max)).forEach(clear);
        }
    }, [max, fifo]);

    return (
        <KeepAliveControllerContext.Provider value={push}>
            {children}
        </KeepAliveControllerContext.Provider>
    );
};

const YourComponent: React.FC = () => null;

keepAlive(YourComponent as React.FC, () => {
    const name = 'unique-key';

    // add this on the place you want control by the max cache size
    const onSave = React.useContext(KeepAliveControllerContext) || undefined;

    // onSave() prop since 0.7.0
    return { name, onSave };
});

// const app = (
//     <KeepAlive.Provider value={/* ... */}>
//         <KeepAliveController max={10}>
//             {/* ... */}
//         </KeepAliveController>
//     </KeepAlive.Provider>
// );
Leecason commented 2 years ago
import * as React from 'react';
import { keepAlive, useIgnoreKeepAlive } from 'react-fiber-keep-alive';

const KeepAliveControllerContext = React.createContext<null | ((name: string) => void)>(null);

export const KeepAliveController: React.FC<{
    max: number;
    children?: React.ReactNode;
}> = ({ max, children }) => {
    const size = React.useRef(max);
    size.current = max;

    const [fifo, setFIFO] = React.useState<string[]>([]);
    const clear = useIgnoreKeepAlive();

    const push = React.useCallback((name: string) => setFIFO((list) => {
        const rest = list.filter((e) => e !== name);
        return [...rest, name];
    }), []);

    React.useEffect(() => {
        if (Number.isFinite(max) && 0 < max) {
            fifo.slice(0, Math.max(0, fifo.length - max)).forEach(clear);
        }
    }, [max, fifo]);

    return (
        <KeepAliveControllerContext.Provider value={push}>
            {children}
        </KeepAliveControllerContext.Provider>
    );
};

const YourComponent: React.FC = () => null;

keepAlive(YourComponent as React.FC, () => {
    const name = 'unique-key';

    // add this on the place you want control by the max cache size
    const onSave = React.useContext(KeepAliveControllerContext) || undefined;

    // onSave() prop since 0.7.0
    return { name, onSave };
});

// const app = (
//     <KeepAlive.Provider value={/* ... */}>
//         <KeepAliveController max={10}>
//             {/* ... */}
//         </KeepAliveController>
//     </KeepAlive.Provider>
// );

感谢~还是希望提供方能原生支持,像 Vue 的 keep-alive 那样

shenjunru commented 2 years ago

每个项目对 cache 的管理会有不同的需求,所以不会加入原生支持。 0.7.0 中已经把 KeepAliveContext 给暴露出来了,不用上面的代码也可以做到全局实现。 可以用其他的 LRU 库对应实现 Map 的几个 API 就可以实现 cache 的 LRU 管理。 用 <KeepAlive.Context.Provider> 代替 <KeepAlive.Provider> 提供 context 即可。 对于TS,之后 0.7.1 中会把用到的 Map 类型抽象成 IMap 接口。