Skip to content
This repository has been archived by the owner on Mar 7, 2024. It is now read-only.

Commit

Permalink
feat: 引入 unstable_useNativeEffect (#557)
Browse files Browse the repository at this point in the history
resolve #310
resolve #255
  • Loading branch information
Darmody authored and yesmeck committed Jan 8, 2020
1 parent b0a6e7d commit be40751
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 3 deletions.
38 changes: 38 additions & 0 deletions docs/guide/framework.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,41 @@ export default () => {
```

你也可以通过小程序原生的方式获取参数(通常在 `onLoad` 方法里获取),包括场景值也是。

### 小程序渲染 Effect

一般在 React 里,我们通过在 `useEffect` 来进行页面渲染成后需要处理的逻辑。但是在 Remax 中,`useEffect` 只是代表了 Remax 虚拟 DOM 处理完成,并不代表小程序渲染完成。
为了支持开发者可以触及小程序渲染完成的时机,我们添加了一个新的 hook:`unstable_useNativeEffect`

```jsx
import * as React from 'react';
import { unstable_useNativeEffect, useShow } from 'remax';

export default () => {
const [width, setWidth] = React.useState(width, 0);
const [height, setHeight] = React.useState(height, 0);

useShow(() => {
setTimeout(() => {
setWidth(100)
}, 3000)

setTimeout(() => {
setHeight(100)
}, 3000)
});
unstable_useNativeEffect(() => {
console.log('width', width, 'height', height);
// 只有在 width 变化时,才执行这个逻辑。
// 建议一定要写 hooks 依赖,否则所有 setData 回调后,都会在这里执行
}, [width])

...
}
```

在上面的例子中:

- 页面首次渲染成功后,会看到 console 输出 `width 0 height 0`
- 3000 ms 后,更新了 width 的值,console 输出 `width 100 height 0`
- 3000 ms 后, 更新了 height 的值,console 没有新的输出。
2 changes: 2 additions & 0 deletions packages/remax/src/Container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { FiberRoot } from 'react-reconciler';
import Platform from './Platform';
import propsAlias from './propsAlias';
import { isHostComponent } from './createHostComponent';
import nativeEffector from './nativeEffect';

function stringPath(path: Path) {
return path.join('.');
Expand Down Expand Up @@ -97,6 +98,7 @@ export default class Container {
}

this.context.setData({ action: tree }, () => {
nativeEffector.run();
/* istanbul ignore next */
if (process.env.REMAX_DEBUG) {
console.log(
Expand Down
65 changes: 63 additions & 2 deletions packages/remax/src/__tests__/alipay/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,16 @@ import { render, View, Input } from '../../../src/adapters/alipay';
import { reset as resetInstanceId } from '../../instanceId';
import { reset as resetActionId } from '../../actionId';
import Container from '../../Container';
// eslint-disable-next-line @typescript-eslint/camelcase
import { unstable_useNativeEffect } from '../../hooks';

const p = {
setData() {
// mock function
setData(state: any, callback: Function) {
setTimeout(() => {
if (typeof callback === 'function') {
callback();
}
});
},
$spliceData() {
// mock function
Expand Down Expand Up @@ -327,4 +333,59 @@ describe('alipay', () => {
done();
}, 5);
});

it('unstable_useNativeEffect once works', done => {
let count = 0;
const Page = () => {
const [width, setWidth] = React.useState(0);
unstable_useNativeEffect(() => {
count += 1;

setTimeout(() => {
if (count === 1) {
done();
}
}, 500);
}, []);
React.useEffect(() => {
setTimeout(() => {
setWidth(100);
}, 100);
}, []);

return <View>{width}</View>;
};
const container = new Container(p);
render(<Page />, container);
});

it('unstable_useNativeEffect deps works', done => {
let count = 0;
const Page = () => {
const [width, setWidth] = React.useState(0);
const [height, setheight] = React.useState(0);
unstable_useNativeEffect(() => {
count += 1;

if (count === 2) {
done();
}
}, [width]);
React.useEffect(() => {
setheight(100);
setTimeout(() => {
setWidth(100);
}, 1000);
}, []);

return (
<View>
{width}
{height}
</View>
);
};
const container = new Container(p);
render(<Page />, container);
});
});
13 changes: 12 additions & 1 deletion packages/remax/src/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import { useLayoutEffect, useContext } from 'react';
import { useLayoutEffect, useContext, DependencyList } from 'react';
import { registerLifecycle, Lifecycle, Callback } from './lifecycle';
import PageInstanceContext from './PageInstanceContext';
import nativeEffect, { Listener } from './nativeEffect';

// eslint-disable-next-line @typescript-eslint/camelcase
export function unstable_useNativeEffect(
listener: Listener,
deps?: DependencyList
) {
useLayoutEffect(() => {
return nativeEffect.connect(listener, !!deps);
}, deps);
}

export function useShow(callback: Callback) {
const pageInstance = useContext(PageInstanceContext);
Expand Down
42 changes: 42 additions & 0 deletions packages/remax/src/nativeEffect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
export type Listener = Function;

interface ListenerConfig {
listener: Listener;
once: boolean;
}

interface NativeEffector {
listenerConfigs: ListenerConfig[];
}

const effector: NativeEffector = {
listenerConfigs: [],
};

function dispose(listener: Listener) {
effector.listenerConfigs = effector.listenerConfigs.filter(
config => config.listener !== listener
);
}

function connect(listener: Listener, once: boolean) {
effector.listenerConfigs.push({ listener, once });

return () => dispose(listener);
}

function run() {
effector.listenerConfigs.forEach(config => {
config.listener();

if (config.once) {
dispose(config.listener);
}
});
}

export default {
connect,
run,
dispose,
};

0 comments on commit be40751

Please sign in to comment.