structurebuilder / react-keep-alive Goto Github PK
View Code? Open in Web Editor NEWA component that maintains component state and avoids repeated re-rendering.
License: MIT License
A component that maintains component state and avoids repeated re-rendering.
License: MIT License
Hello
由于 react-keep-alive
原理大致为将 KeepAlive children
提取出来渲染到 <KeepAliveProvider />
节点下,而非 <KeepAlive />
之下
这将导致 KeepAlive
中的组件无法被 React
认为是在其所处的上下文之中
样例大致如下:
https://codesandbox.io/s/basic-currently-rwo9y
import React, { createContext, useState } from "react";
import ReactDOM from "react-dom";
import { Provider as KeepAliveProvider, KeepAlive } from "react-keep-alive";
const { Provider, Consumer } = createContext();
function Test({ contextValue = null }) {
return (
<div>
<p>contextValue: {contextValue}</p>
</div>
);
}
function App() {
const [show, setShow] = useState(true);
const toggle = () => setShow(show => !show);
return (
<KeepAliveProvider>
<div>
<Provider value={1}>
{show && (
<KeepAlive name="Test">
<Consumer>
{context => <Test contextValue={context} />}
</Consumer>
</KeepAlive>
)}
<button onClick={toggle}>toggle</button>
</Provider>
</div>
</KeepAliveProvider>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
样例中的 <Test />
无法从 <Consumer />
中获得 contextValue
属性
从实现原理上来说目前似乎无法避免,是不得已而为之
想问问在这方面有没有考虑其他可能的实现方式呢?
目前会对直觉上的 Context
造成破坏,有不小的危害性,如果目前无法修复的话,个人认为有必要在 README 中给出警示
测试时发现这个情况
使用 <KeepAlive />
包裹长列表组件后,列表滚动至底部并触发 keep-alive
,缓存恢复时,长列表的 scrollTop
恢复为 0
猜测和 createPortal
工作方式有关,或者是不是我的使用方式有误?
用了antd样式,然后发现为什么缓存了之后,只要选择了有滚动条的页面,然后进入其他页面,发现底部有空白区,这怎么解决?
考虑到keep alive的组件不会被回收,将常驻内存,如果用户长时间使用,势必会存在占用大量内存。因此希望可以有办法限制alive组件数量。
尝试过动态修改provider的include,不过不生效。建议可以在include值变化后,清理不符合include规则的alive组件移除。
@Sam618 麻烦看下有没有什么办法解决,实际工程中应用比较迫切需要解决的问题
#12 (comment)
我按照这个配置页面可以使用Link了,但this.props.history后路径发生变化了,但内容没有变化
我在next.js 上使用报错 document is not defined
ReferenceError: document is not defined
at Object.createStoreElement [as default] (/Users/panghongye/Desktop/Project/bemular-saas-website/node_modules/_react-keep-alive@2.1.0@react-keep-alive/cjs/utils/createStoreElement.js:5:24)
at new KeepAliveProvider (/Users/panghongye/Desktop/Project/bemular-saas-website/node_modules/_react-keep-alive@2.1.0@react-keep-alive/cjs/components/Provider.js:49:58)
at processChild (/Users/panghongye/Desktop/Project/bemular-saas-website/node_modules/_react-dom@16.8.6@react-dom/cjs/react-dom-server.node.development.js:2846:14)
at resolve (/Users/panghongye/Desktop/Project/bemular-saas-website/node_modules/_react-dom@16.8.6@react-dom/cjs/react-dom-server.node.development.js:2812:5)
at ReactDOMServerRenderer.render (/Users/panghongye/Desktop/Project/bemular-saas-website/node_modules/_react-dom@16.8.6@react-dom/cjs/react-dom-server.node.development.js:3202:22)
at ReactDOMServerRenderer.read (/Users/panghongye/Desktop/Project/bemular-saas-website/node_modules/_react-dom@16.8.6@react-dom/cjs/react-dom-server.node.development.js:3161:29)
at renderToString (/Users/panghongye/Desktop/Project/bemular-saas-website/node_modules/_react-dom@16.8.6@react-dom/cjs/react-dom-server.node.development.js:3646:27)
at render (/Users/panghongye/Desktop/Project/bemular-saas-website/node_modules/_next-server@8.1.0@next-server/dist/server/render.js:86:16)
at renderPage (/Users/panghongye/Desktop/Project/bemular-saas-website/node_modules/_next-server@8.1.0@next-server/dist/server/render.js:211:20)
at Function.value (/Users/panghongye/Desktop/Project/bemular-saas-website/.next/server/static/development/pages/_document.js:555:41)
at Object.loadGetInitialProps (/Users/panghongye/Desktop/Project/bemular-saas-website/node_modules/_next-server@8.1.0@next-server/dist/lib/utils.js:42:35)
at Object.renderToHTML (/Users/panghongye/Desktop/Project/bemular-saas-website/node_modules/_next-server@8.1.0@next-server/dist/server/render.js:218:36)
KeepAlive 内部组件使用 react-router-dom 的 with�Router 高阶组件 获取的 path/url/params 都是 '/' ---> {path: "/", url: "/", params: {…}, isExact: false}
我需要作者的技术指导,正在阅读修改源码,
感谢作者写出这么强大的库,但是在我的业务应用场景中(非常复杂),需要改动,所以想了解下这个库整体的架构设计思路。 替换规则,可以简要说明一下吗?我打算应用在我比较复杂的项目中。
const [value,setValue] = useState('');
const change = (e) => {
setValue(e.target.value);
}
return (
<input onChange={(e) => { change(e) }} />
value:{value}
请问这个有什么好的解决办法不
// 目前只能这样
function useReady() {
const [ready, setReady] = useState(false);
useEffect(() => {
setReady(true);
}, []);
return ready;
}
function Component() {
const ready = useReady();
const child = (......);
const keepAlive = <KeepAlive name={...}>{child}</KeepAlive>;
return <Provider>
{!ready ? child : keepAlive}
</Provider>
}
这步操作应该在内部完成:
export function KeepAlive() {
const ready = useReady();
return !ready ? renderImmediate() : normalRender();
}
目前服务端只能渲染空节点。
在工作中,由详情页调到列表页,列表页需要缓存,但从修改业到列表页,列表页不需要缓存,需要动态控制,麻烦能不能给个demo,关于disable的
现在的生命周期,我认为其实有些怪异:
Mounting: componentWillMount -> componentDidMount
Unmounting: componentWillUnmount
Activating: componentWillUpdate -> componentDidMount(This is where the user is confused. I am tampering with the life cycle when I activate it.)
Unactivating: componentWillUnmount
在 Activating 时,其实组件并没有真正的卸载掉,所以能够保存组件实例中的状态;这个阶段本来的执行顺序是 componentWillUpdate -> componentDidUpdate
,但是为了方便,我更改了生命周期,这样就与 React 的生命周期有些不一样,不知道大家能否接受,希望能提出一些建议😄。
window.location.href这种跳转,返回还能缓存吗?
跳转之后返回是不是不应该触发componentDidMount?但是每次都触发了这个生命周期,
import { Provider } from 'react-redux';
...
,
import 的时候出现这个问题,按照文档来的,结果报错了。中午用的还好好的。请问是什么原因造成的。重新安装npm包也是失败的
这是我的部分路由配置,通过其属性keepAlive获取需要缓存的组件name,初次页面可以渲染,但是跳转到其他页面
import React from 'react';
import { Switch, Route } from 'react-router-dom';
import routers from 'routes.js';
import {
Provider as KeepAliveProvide,
KeepAlive
} from 'react-keep-alive';
const keepAliveList = routers.map(d => d.keepAlive && d.name);
class RoutesList extends React.Component {
render() {
let constRoute = routers.map((item, index) => {
return (
<KeepAlive name={item.name} key={item.name + index}>
<Route exact={true} key={index} path={item.path} name={item.name} component={item.component}>
</Route>
</KeepAlive>
);
});
return (
<div>
<Switch>
<KeepAliveProvide include={keepAliveList}>
{constRoute}
</KeepAliveProvide>
</Switch>
</div>
);
}
}
export default RoutesList;
<main>
<Switch>
<Route path="/" exact render={() => <Redirect to="/map" />} /> ,
<Route exact path="/map">
<KeepAlive name="map">
<MapWrap /> // 百度地图封装 style: { width: 100%, height: 100%}
</KeepAlive>
</Route> ,
</Switch>
</main>
我观察到 <KeepAlive name="map">
初始化时会有个 div 。初始化时结构大致为
<main>
<div> // <-- KeppAlive 初始化时生成
<MapWrap /> // style: { width: 100%, height: 100%}
</div>
</main>
完成初始化
<main>
<MapWrap /> // style: { width: 100%, height: 100%}
</main>
百度地图初始化时会计算绑定 DOM( MapWrap
) 的宽高,然后根据这个宽高生成相应的坐标,及中心点坐标。
由于加入的这个 Div
导致 <MapWrap />
宽高 style: { width: 100%, height: 100%}
计算出来是 0。从而导致百度地图初始化后 坐标点 错误。
这个坑挺隐蔽的~ 找了我2天 =。=
initClassName
的 Props
,然后用户自行在 CSS 里面处理前一种办法简单粗暴,后面一种适用范围更广吧(万一有人的需求要在 初始化时 js 操作 Dom 等极端情况)
项目中使用 const OrderRecord = lazy(() => import('%/order/record.jsx')) 引入的组件使用react-keep-alive 不显示。生命周期会走,render不出界面???
移动端项目使用react
太大,preact
目前版本没有createContext
,暂时使用的preact-context-provider
第三方包。
但是我也想用react-keep-alive
,有什么办法可以兼容一下吗
App.tsx
import React, { useEffect } from 'react';
import {
Provider as KeepAliveProvider,
} from 'react-keep-alive'
import Login from './pages/login/Login';
import Index from './pages/index/Index';
import Post from './pages/post/Post'
import Info from './pages/info/Info'
import Person from './pages/person/Person'
import Chat from './pages/chat/Chat'
import {
BrowserRouter as Router,
Route,
} from 'react-router-dom';
import Store from './store'
const App: React.FC = () => {
return (
<Store>
<Router>
<KeepAliveProvider>
<Route exact path="/" component={Index} />
<Route exact path="/login" component={Login} />
<Route exact path="/post" component={Post} />
<Route exact path="/info" component={Info} />
<Route exact path="/person" component={Person} />
<Route exact path="/chat" component={Chat} />
</KeepAliveProvider>
</Router>
</Store>
);
}
export default App;
demo.tsx:
...
import {useKeepAliveEffect} from 'react-keep-alive';
// 下拉到底部触发更新
const loadCallback = () => {
setPage(page => page + 1)
getCirclePost()
}
useLayoutEffect(() => {
initCirclePost()
}, []) // eslint-disable-line
useKeepAliveEffect(() => {
return () => {
};
});
...
TypeError:
TypeError: Cannot read property 'on' of undefined
at useKeepAliveEffect.js:22
at ma (react-dom.production.min.js:4439)
at react-dom.production.min.js:5048
at Wa (react-dom.production.min.js:5067)
at ui (react-dom.production.min.js:3473)
at Index.tsx:70
at c (runtime.js:45)
at Generator._invoke (runtime.js:264)
at Generator.e.<computed> [as next] (runtime.js:98)
at r (asyncToGenerator.js:3)
package.json
"dependencies": {
"@babel/core": "7.4.3",
"@babel/plugin-transform-react-jsx-self": "^7.2.0",
"@babel/plugin-transform-react-jsx-source": "^7.5.0",
"@svgr/webpack": "4.1.0",
"@types/jest": "24.0.15",
"@types/node": "12.6.8",
"@types/react": "16.8.23",
"@types/react-dom": "16.8.5",
"@types/react-router-dom": "^4.3.4",
"@typescript-eslint/eslint-plugin": "1.6.0",
"@typescript-eslint/parser": "1.6.0",
"axios": "^0.19.0",
"babel-eslint": "10.0.1",
"babel-jest": "^24.8.0",
"babel-loader": "8.0.5",
"babel-plugin-named-asset-import": "^0.3.2",
"babel-preset-react-app": "^9.0.0",
"camelcase": "^5.2.0",
"case-sensitive-paths-webpack-plugin": "2.2.0",
"css-loader": "2.1.1",
"dotenv": "6.2.0",
"dotenv-expand": "4.2.0",
"eslint": "^5.16.0",
"eslint-config-react-app": "^4.0.1",
"eslint-loader": "2.1.2",
"eslint-plugin-flowtype": "2.50.1",
"eslint-plugin-import": "2.16.0",
"eslint-plugin-jsx-a11y": "6.2.1",
"eslint-plugin-react": "7.12.4",
"eslint-plugin-react-hooks": "^1.5.0",
"file-loader": "3.0.1",
"fs-extra": "7.0.1",
"html-webpack-plugin": "4.0.0-beta.5",
"identity-obj-proxy": "3.0.0",
"is-wsl": "^1.1.0",
"jest": "24.7.1",
"jest-environment-jsdom-fourteen": "0.1.0",
"jest-resolve": "24.7.1",
"jest-watch-typeahead": "0.3.0",
"mini-css-extract-plugin": "0.5.0",
"node-sass": "^4.12.0",
"optimize-css-assets-webpack-plugin": "5.0.1",
"pnp-webpack-plugin": "1.2.1",
"postcss-flexbugs-fixes": "4.1.0",
"postcss-loader": "3.0.0",
"postcss-normalize": "7.0.1",
"postcss-preset-env": "6.6.0",
"postcss-safe-parser": "4.0.1",
"react": "^16.8.6",
"react-app-polyfill": "^1.0.1",
"react-dev-utils": "^9.0.1",
"react-dom": "^16.8.6",
"react-keep-alive": "^2.4.2",
"react-router-dom": "^5.0.1",
"redell-ui": "^0.2.7",
"resolve": "1.10.0",
"sass-loader": "7.1.0",
"semver": "6.0.0",
"style-loader": "0.23.1",
"terser-webpack-plugin": "1.2.3",
"ts-pnp": "1.1.2",
"typescript": "^3.4.3",
"url-loader": "1.1.2",
"use-react-router": "^1.0.7",
"webpack": "4.29.6",
"webpack-dev-server": "3.2.1",
"webpack-manifest-plugin": "2.0.4",
"workbox-webpack-plugin": "4.2.0"
},
在KeepAlive 中 使用name属性 来回切换组件 就报错。使用key就不报错
因为要考虑到切换用户重新登入时,页面缓存可能要重置到用户刚进入时的状态。
想问下有没有什么方法能手动清空页面缓存
react 在15.6.2版本会出现React.createContext is not a function问题,请问有版本兼容吗?
当我使用useSatate设置的值 在useKeepAliveEffect 中获取的值永远是初始值
有捐赠,才能健康的发展
试着用bindLifeCycle拦截,手动处理scroll restore,发现在componentWillUnactivate的时候,scrollTop就意外地变成了0
而在onScroll里面每次scroll后记录位置,也会在unactivate后变成0,似乎在挂载到别的地方的时候重新scroll了。
At present, there are some problems in implementation. The biggest problem is that context can not be easily accessed.
Therefore, I hope to solve this problem through refactoring, I do not know what better ideas you have?
作者您好,
操作系统:CentOS 7.5
node: 10.15.3
打包工具:umi
生成文件出现
错误位置
react-keep-alive/src/utils/keepAlive.tsx
Line 278 in e95cef4
// _app.js
import React from "react";
import { Provider } from "react-redux";
import { Provider as KeepProvider } from "react-keep-alive";
import App, { Container } from "next/app";
import withReduxStore from "../lib/with-redux-store";
class Huaban extends App {
render() {
const { Component, pageProps, reduxStore } = this.props;
return (
<Container>
<Provider store={reduxStore}>
<KeepProvider include="Example">
<Component {...pageProps} />
</KeepProvider>
</Provider>
</Container>
);
}
}
export default withReduxStore(Huaban);
// example.js
import Link from "next/link";
import { KeepAlive } from "react-keep-alive";
let arr = Array.from({ length: 200 }, (v, i) => i);
export default () => (
<KeepAlive name="Example">
<ul>
{arr.map((v, i) => {
const href = `item?id=${i}`;
<Link href={href}>
<a>
<li>item{i}</li>
</a>
</Link>;
})}
</ul>
</KeepAlive>
);
Document and Window don't exist in Node server.
错误提示: react-dom.production.min.js:110 DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
代码
import { HashRouter, Route, Switch } from 'react-router-dom';
import {
Provider as KeepAliveProvider,
KeepAlive,
} from 'react-keep-alive';
import App from '../pages/app';
import Demo from '../pages/demo';
const Router = (
);
export default Router;
main.js
import Api from './api/index';
import Util from './utils';
import Router from './routes';
import 'antd/dist/antd.css';
Object.assign(global, antd);
global.Api = Api;
global.Util = Util;
ReactDOM.render(
Router,
document.getElementById('app'),
);
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.