Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/shenjunru/react-fiber-keep-alive

A component that maintains component state and avoids repeated re-rendering.
https://github.com/shenjunru/react-fiber-keep-alive

keep-alive react react-dom react-fiber

Last synced: about 2 months ago
JSON representation

A component that maintains component state and avoids repeated re-rendering.

Awesome Lists containing this project

README

        

# Keep-Alive for `React DOM`

[![npm](https://img.shields.io/npm/v/react-fiber-keep-alive.svg?style=for-the-badge)](http://npm.im/react-fiber-keep-alive)
[![downloads](https://img.shields.io/npm/dm/react-fiber-keep-alive.svg?style=for-the-badge)](https://www.npmjs.com/package/react-fiber-keep-alive)
[![typescript](https://img.shields.io/badge/language-typescript-blue?style=for-the-badge)](https://www.typescriptlang.org/)
[![LICENSE](https://img.shields.io/npm/l/react-fiber-keep-alive.svg?style=for-the-badge)](https://github.com/shenjunru/react-fiber-keep-alive/blob/main/LICENSE)

`` is a component that maintains component state and avoids repeated re-rendering.

## ✨ Features
- [x] Only based on `React Fiber` and `React Hooks`.
- [x] Triggers original class component life circle.
- [x] Triggers original effect hooks.
- [x] Supports context updates.
- [x] Supports multiple `keep-alive`.
- [x] Supports `react-dom` v16.8+.
- [x] Supports `react-dom` v17.
- [x] Supports `react-dom` v18.

## 📦 Installation

```bash
npm install --save react-fiber-keep-alive
```

## 🔨 Usage

```JavaScript
import React from 'react';
import ReactDOM from 'react-dom';
import KeepAlive from 'react-fiber-keep-alive';

const root = document.getElementById('root');

ReactDOM.render((

...



...

), root);
```

## 📝 API

- Provide `root` container element.
```JSX

```
- Must be the root container of `render()`.
- If not provided, `keep-alive` will be disabled.

- Wrap your component with ``
```JSX



```
- prop "name" is a required unique string used to identify the cache.
- prop "ignore" is a optional boolean used to bypass and clear the cache. (since 0.5.0)
- prop "onRead(name: string): void" is a optional callback after cache applied. (since 0.7.0)
- prop "onSave(name: string): void" is a optional callback after cache saved. (since 0.7.0)

- Wrap your component with `keepLive()`.
```JavaScript
import { keepAlive } from 'react-fiber-keep-alive';

const NewComponent = keepAlive(YourComponent, (props) => {
// props: the income props for ``

// you can use react hooks here

return `unique-key`;

// or

return {
name: `unique-key`,
// other props for ``
};
});
```

- Hook: `useIgnoreKeepAlive()` returns a cache cleaner function.
```JavaScript
import { useIgnoreKeepAlive } from 'react-fiber-keep-alive';

const ignoreCache = useIgnoreKeepAlive();

ignoreCache(`unique-key`);
```

- If the `render()` of class component has side effects.
```JavaScript
import { markClassComponentHasSideEffectRender } from 'react-fiber-keep-alive';

markClassComponentHasSideEffectRender(ClassComponent);

// Example:
class Test extends React.Component {
render() {
// side effect here, ex: emit event here.
return null;
}
}
markClassComponentHasSideEffectRender(Test);
```

- If no need to trigger the effect hook while remounting.
```JavaScript
import { markEffectHookIsOnetime } from 'react-fiber-keep-alive';

markEffectHookIsOnetime(effectHook);

// Example:
React.useEffect(markEffectHookIsOnetime(() => {
// do something
}), []);
React.useLayoutEffect(markEffectHookIsOnetime(() => {
// do something
}), []);
```

- `KeepAlive.Context` (since 0.7.0)
```TSX
import * as React from 'react';
import KeepAlive, { Context, KeepAliveCache } from 'react-fiber-keep-alive';
import LRUCache from 'lru-cache';

/// Example: Use LRU to manage the cache
const YourKeepAliveProvider: React.FC<{
children: React.ReactNode;
value: null | HTMLElement;
}> = (props) => {
const container = props.value;
const context: Context = React.useMemo(() => {
if (!container) {
return [];
}
const caches = new LRUCache({
max: 10,
});
return [container, caches, new Map()];
}, []);

return (

{props.children}

);
};
```

## 💡 Tips

- Be careful the global side effects. (ex: insert global style)
- Do not use `` under the ``.
- Recursive `` handled by top level ``.
- If the `container` changed in `ReactDOM.createPortal(children, container)`.
- All saved sub tree state will be lost.
- Errors from `react-devtools` after `` remounted.
- Try force refresh the components tree. (ex: updates components filter)

## 🏁 Tested

### Examples
- [react-router v5](https://codesandbox.io/s/keep-alive-react-router-example-hfbbi7)

### React v16.8+ / v17 / v18
- [x] `render(children, container)`
- [x] `hydrate(children, container)`

### React v18 (concurrent mode)
- [x] `createRoot(container).render(children)`
- [x] `hydrateRoot(container, children)`

### Class Component
- [x] `Component.getDerivedStateFromProps()`
- [x] `Component.getDerivedStateFromError()`
- [x] `instance.componentDidMount()`
- [x] `instance.getSnapshotBeforeUpdate()`
- [x] `instance.componentDidUpdate()`
- [x] `instance.componentWillUnmount()`
- [x] `instance.render()`

### Function Component
- [x] `useContext()`
- [x] `useCallback()`
- [x] `useEffect()`
- [x] `useImperativeHandle()`
- [x] `useLayoutEffect()`
- [x] `useMemo()`
- [x] `useRef()`
- [x] `useState()`
- [ ] `useDebugValue()`
- [ ] `useDeferredValue()` (since v18)
- [ ] `useId()` (since v18)
- [x] `useInsertionEffect()` (since v18)
- [ ] `useSyncExternalStore()` (since v18)
- [ ] `useTransition()` (since v18)

### Other
- [x] `ReactDOM.createPortal(children, container)`
- [x] `React.memo()`
- [x] `React.forwardRef()`
- [x] `React.lazy()`
- [x] ``
- [ ] `` (since v18)

## 🐛 Issues

If you find a bug, please file an issue on [our issue tracker on GitHub](https://github.com/shenjunru/react-fiber-keep-alive/issues).

## 📄 License

Copyright © 2022 [**Shen Junru**](https://github.com/shenjunru) • [**MIT license**](LICENSE).