Skip to content

Commit

Permalink
Merge pull request #11 from CJY0208/develop
Browse files Browse the repository at this point in the history
增加 AliveScope 外部告警;修复 saveScrollPosition 失效问题(缺失 value 函数);修复 saveScr…
  • Loading branch information
CJY0208 authored Nov 11, 2019
2 parents 273e056 + 4301049 commit 75af7f7
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 84 deletions.
71 changes: 39 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ npm install react-activation

## Usage

Add `react-activation/babel` plugins in `.babelrc`
#### 1. Add `react-activation/babel` plugins in `.babelrc`

The plugin adds a `_ka` attribute to each JSX element during compilation to help the `<KeepAlive />` runtime generate a unique identifier by render location.
The plugin adds a `_ka` attribute to each JSX element during compilation to help the `react-activation` runtime **generate an unique identifier by render location**.

```javascript
{
Expand All @@ -52,57 +52,64 @@ The plugin adds a `_ka` attribute to each JSX element during compilation to help
}
```

In your business code
#### 2. In your business code, place the `<AliveScope>` outer layer at a location that will not be unmounted, usually at the application entrance

Note: When used with `react-router` or `react-redux`, you need to place `<AliveScope>` inside `<Router>` or `<Provider>`

```javascript
import React, { Component, useState } from 'react'
// entry.js

import React from 'react'
import ReactDOM from 'react-dom'
import KeepAlive, { AliveScope, withActivation } from 'react-activation'
import { AliveScope } from 'react-activation'

@withActivation
class Test extends Component {
state = {
count: 0
}
import Test from './Test'

setCount = count => this.setState({ count })
ReactDOM.render(
<AliveScope>
<Test />
</AliveScope>,
document.getElementById('root')
)
```

componentDidActivate() {
console.log('Test: componentDidActivate')
}
#### 3. Wrap the components that need to keep states with `<KeepAlive>`

componentWillUnactivate() {
console.log('Test: componentWillUnactivate')
}
Like the `<Counter>` component in the example

render() {
const { count } = this.state

return (
<div>
count: {count}
<button onClick={() => this.setCount(count + 1)}>add</button>
</div>
)
}
```javascript
// Test.js

import React, { useState } from 'react'
import KeepAlive from 'react-activation'

function Counter() {
const [count, setCount] = useState(0)

return (
<div>
<p>count: {count}</p>
<button onClick={() => setCount(count => count + 1)}>Add</button>
</div>
)
}

function App() {
function Test() {
const [show, setShow] = useState(true)

return (
<AliveScope>
<div>
<button onClick={() => setShow(show => !show)}>Toggle</button>
{show && (
<KeepAlive>
<Test />
</KeepAlive>
)}
</AliveScope>
</div>
)
}

ReactDOM.render(<App />, document.getElementById('root'))
export default Test
```

- - -
Expand All @@ -117,7 +124,7 @@ Use `componentDidActivate` and `componentWillUnactivate` to correspond to the tw

```javascript
...
import KeepAlive, { useActivate, useUnactivate withActivation } from 'react-activation'
import KeepAlive, { useActivate, useUnactivate, withActivation } from 'react-activation'

@withActivation
class TestClass extends Component {
Expand Down
74 changes: 41 additions & 33 deletions README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,17 @@ Vue 中 `<keep-alive />` 功能在 React 中的实现

```bash
yarn add react-activation
# or
# 或者
npm install react-activation
```

- - -

## 使用方式

`.babelrc` 中增加 `react-activation/babel` 插件
#### 1. babel 配置文件 `.babelrc` 中增加 `react-activation/babel` 插件

该插件会于编译阶段在各 JSX 元素上增加 `_ka` 属性,帮助 KeepAlive 运行时按渲染位置生成唯一的缓存 id 标识
该插件会于编译阶段在各 JSX 元素上增加 `_ka` 属性,帮助 `react-activation` 在运行时**按渲染位置生成唯一的缓存 id 标识**

```javascript
{
Expand All @@ -52,57 +53,64 @@ npm install react-activation
}
```

业务代码中
#### 2. 业务代码中,在不会被销毁的位置放置 `<AliveScope>` 外层,一般为应用入口处

注意:与 `react-router``react-redux` 配合使用时,需要将 `<AliveScope>` 放置在 `<Router>``<Provider>` 内部

```javascript
import React, { Component, useState } from 'react'
// entry.js

import React from 'react'
import ReactDOM from 'react-dom'
import KeepAlive, { AliveScope, withActivation } from 'react-activation'
import { AliveScope } from 'react-activation'

@withActivation
class Test extends Component {
state = {
count: 0
}
import Test from './Test'

setCount = count => this.setState({ count })
ReactDOM.render(
<AliveScope>
<Test />
</AliveScope>,
document.getElementById('root')
)
```

componentDidActivate() {
console.log('Test: componentDidActivate')
}
#### 3. 用 `<KeepAlive>` 包裹需要保持状态的组件

componentWillUnactivate() {
console.log('Test: componentWillUnactivate')
}
如例子中的 `<Counter>` 组件

render() {
const { count } = this.state

return (
<div>
count: {count}
<button onClick={() => this.setCount(count + 1)}>add</button>
</div>
)
}
```javascript
// Test.js

import React, { useState } from 'react'
import KeepAlive from 'react-activation'

function Counter() {
const [count, setCount] = useState(0)

return (
<div>
<p>count: {count}</p>
<button onClick={() => setCount(count => count + 1)}>Add</button>
</div>
)
}

function App() {
function Test() {
const [show, setShow] = useState(true)

return (
<AliveScope>
<div>
<button onClick={() => setShow(show => !show)}>Toggle</button>
{show && (
<KeepAlive>
<Test />
</KeepAlive>
)}
</AliveScope>
</div>
)
}

ReactDOM.render(<App />, document.getElementById('root'))
export default Test
```

- - -
Expand All @@ -117,7 +125,7 @@ ReactDOM.render(<App />, document.getElementById('root'))

```javascript
...
import KeepAlive, { useActivate, useUnactivate withActivation } from 'react-activation'
import KeepAlive, { useActivate, useUnactivate, withActivation } from 'react-activation'

@withActivation
class TestClass extends Component {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-activation",
"version": "0.3.1",
"version": "0.3.2",
"description": "<KeepAlive /> for React like <keep-alive /> in vue",
"main": "index.js",
"scripts": {
Expand Down
6 changes: 3 additions & 3 deletions src/core/KeepAlive.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import saveScrollPosition from '../helpers/saveScrollPosition'
const getErrorTips = name =>
`<KeepAlive ${
name ? `name="${name}" ` : ''
}/> 瞬时更新次数过多,可能遇到了更新的死循环,已强制暂停更新
您现在可见的更新结果存在严重的性能问题
可能遇到了隐含的 bug,请不要使用 KeepAlive 并联系作者解决`
}/> Too many transient updates, may have encountered an infinite loop of updates, forced to pause the update
There are serious performance issues with the update results you are currently seeing
May encounter an implied bug, please don't use KeepAlive and contact the author to solve`

const parseWhenResult = res => {
if (isArray(res)) {
Expand Down
40 changes: 28 additions & 12 deletions src/core/withAliveScope.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { forwardRef, useContext } from 'react'
import hoistStatics from 'hoist-non-react-statics'

import { isFunction } from '../helpers'
import { get, isFunction, isUndefined } from '../helpers'

import { Acceptor } from './Bridge'
import AliveIdProvider from './AliveIdProvider'
Expand All @@ -13,17 +13,33 @@ function controllerCherryPick(controller) {
}

export const expandKeepAlive = KeepAlive => {
const renderContent = ({ idPrefix, helpers, props }) => (
<AliveIdProvider prefix={idPrefix} key={props._ka}>
{id => (
<Acceptor id={id}>
{bridgeProps => (
<KeepAlive key={id} {...props} {...bridgeProps} id={id} _helpers={helpers} />
)}
</Acceptor>
)}
</AliveIdProvider>
)
const renderContent = ({ idPrefix, helpers, props }) => {
const isOutsideAliveScope = isUndefined(helpers)

if (isOutsideAliveScope) {
console.error('You should not use <KeepAlive /> outside a <AliveScope>')
}

return isOutsideAliveScope ? (
get(props, 'children', null)
) : (
<AliveIdProvider prefix={idPrefix} key={props._ka}>
{id => (
<Acceptor id={id}>
{bridgeProps => (
<KeepAlive
key={id}
{...props}
{...bridgeProps}
id={id}
_helpers={helpers}
/>
)}
</Acceptor>
)}
</AliveIdProvider>
)
}
const HookExpand = ({ id: idPrefix, ...props }) =>
renderContent({ idPrefix, helpers: useContext(aliveScopeContext), props })

Expand Down
6 changes: 6 additions & 0 deletions src/helpers/base/try/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,9 @@ export const run = (obj, keys = [], ...args) => {

return isFunction(func) ? func.call(context, ...args) : func
}

export const value = (...values) =>
values.reduce(
(value, nextValue) => (isUndefined(value) ? run(nextValue) : run(value)),
undefined
)
9 changes: 6 additions & 3 deletions src/helpers/saveScrollPosition.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ import { isArray, isFunction, isExist } from './base/is'
import { flatten } from './utils'

const body = get(root, 'document.body')
const screenScrollingElement = get(
root,
'document.scrollingElement',
get(root, 'document.documentElement', {})
)

function isScrollableNode(node = {}) {
if (!isExist(node)) {
Expand All @@ -30,9 +35,7 @@ export default function saveScrollPosition(from, screenInclude) {
...new Set([
...flatten((!isArray(from) ? [from] : from).map(getScrollableNodes)),
...(screenInclude
? [get(root, 'document.documentElement', {}), body].filter(
isScrollableNode
)
? [screenScrollingElement, body].filter(isScrollableNode)
: [])
])
]
Expand Down

0 comments on commit 75af7f7

Please sign in to comment.