Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow useCode 1st parameter to return undefined, null or an array #455

Merged
merged 9 commits into from Nov 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 16 additions & 3 deletions docs/pages/09.code.md
Expand Up @@ -39,14 +39,27 @@ or:
The `useCode` hook acts as an alternative to the `Animated.Code` component.

```js
Animated.useCode(() => node, deps);
Animated.useCode(
() => Node | Node[] | boolean | null | undefined,
[...dependencies]
)
```

It's passed an animated node and an array of dependencies, and updates that node both when the component mounts and every time a value in that array changes. It does nothing on versions of React Native that don't support hooks (<0.59).
It's passed as 1st parameter a factory function that should return an optional animated node, or array of nodes (which will be then placed in a `block` node), and as 2nd parameter, an array of dependencies. It will update that node, both when the component mounts and every time a value in that array changes. It does nothing on versions of React Native that don't support hooks (<0.59).

```js
const [animated, setAnimated] = React.useState(false);
const [offset, setOffset] = React.useState(20);
Animated.useCode(() => set(transX1, add(_transX, offset)), [offset]);

Animated.useCode(
() => (
animated && [
//...
set(transX1, add(_transX, offset))
]
),
[animated, offset]
);
```

We recommend to use `useCode()` with the `react-hooks/exhaustive-deps` [eslint rule](https://www.npmjs.com/package/eslint-plugin-react-hooks).
4 changes: 3 additions & 1 deletion react-native-reanimated.d.ts
@@ -1,6 +1,8 @@
// Project: https://github.com/software-mansion/react-native-reanimated
// TypeScript Version: 2.8

type Nullable<T> = T | null | undefined;

declare module 'react-native-reanimated' {
import { ComponentClass, ReactNode, Component } from 'react';
import {
Expand Down Expand Up @@ -329,7 +331,7 @@ declare module 'react-native-reanimated' {

// hooks
export function useCode(
exec: () => AnimatedNode<number>,
exec: () => Nullable< AnimatedNode<number>[] | AnimatedNode<number> > | boolean,
deps: Array<any>,
): void

Expand Down
57 changes: 40 additions & 17 deletions src/derived/useCode.js
@@ -1,20 +1,43 @@
import React from 'react';
import { always } from '../base';
import { always, block } from '../base';

function useCode(exec, deps) {
if (typeof React.useEffect === 'function') {
React.useEffect(() => {
if (typeof exec !== 'function') {
console.warn(
'useCode() first argument should be a function that returns an animation node.'
);
}
const animatedAlways = always(typeof exec === 'function' ? exec() : exec);
animatedAlways.__attach();
return () => {
animatedAlways.__detach();
};
}, deps);
}
/**
* @callback NodeFactory
* Function to create a node or an array of nodes.
* @returns {(Node[] | Node | null | undefined | Boolean)}
*/

/**
* React hook to run a node.
* @param {NodeFactory} nodeFactory Function to build the node to run.
* @param dependencies Array of dependencies. Refresh the node on changes.
*/
export default function useCode(nodeFactory, dependencies) {
if (!(React.useEffect instanceof Function))
return;

React.useEffect(() => {
// check and correct 1st parameter
if (!(nodeFactory instanceof Function)) {
console.warn('useCode() first argument should be a function that returns an animation node.');

const node = nodeFactory;
nodeFactory = () => node;
}

let node = nodeFactory();
if (node) {
// allow factory to return array
if (node instanceof Array)
node = block(node);

const animatedAlways = always(node);
animatedAlways.__attach();

// return undo function
return () => animatedAlways.__detach();
}
},
dependencies
);
}
export default useCode;