diff --git a/README.md b/README.md index 2346e1a4..cb915edd 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,7 @@
- [**State**](./docs/State.md) - [`createMemo`](./docs/createMemo.md) — factory of memoized hooks. + - [`useAdopt`](./docs/useAdopt.md) — extract value from multiple render-prop (or FaCC) components. - [`useCallbag`](./docs/useCallbag.md) — tracks latest value of a callbag. - [`useGetSet`](./docs/useGetSet.md) — returns state getter `get()` instead of raw state. - [`useGetSetState`](./docs/useGetSetState.md) — as if [`useGetSet`](./docs/useGetSet.md) and [`useSetState`](./docs/useSetState.md) had a baby. diff --git a/docs/useAdopt.md b/docs/useAdopt.md new file mode 100644 index 00000000..986ded6f --- /dev/null +++ b/docs/useAdopt.md @@ -0,0 +1,35 @@ +# `useAdopt` + +Extracts a values from multiple render-prop or FaCC components. +This hook is similar to [`useRenderProp`](./useRenderProp.md), but +it allows to specify a named map of multiple render-prop elements +from which to extract values. + + +## Usage + +```jsx +import {useAdopt} from 'react-use'; + +const FaCC = ({children}) => { + return children('VALUE-FaCC'); +}; +const RenderProp = ({render}) => { + return render('VALUE-RenderProp'); +}; + +const Demo = () => { + const [fragment, result] = useAdopt({ + facc: , + renderProp: , + }); + + return ( + <> + {fragment} +
FaCC: {result.facc[0]}
+
Render prop: {result.renderProp[0]}
+ + ); +}; +``` diff --git a/src/__stories__/useAdopt.story.tsx b/src/__stories__/useAdopt.story.tsx new file mode 100644 index 00000000..5fe91eaf --- /dev/null +++ b/src/__stories__/useAdopt.story.tsx @@ -0,0 +1,32 @@ +import {storiesOf} from '@storybook/react'; +import * as React from 'react'; +import {useAdopt} from '..'; +import ShowDocs from '../util/ShowDocs'; + +const FaCC = ({children}) => { + return children('VALUE-FaCC'); +}; +const RenderProp = ({render}) => { + return render('VALUE-RenderProp'); +}; + +const Demo = () => { + const [fragment, result] = useAdopt({ + facc: , + renderProp: , + }); + + return ( + <> + {fragment} +
FaCC: {result.facc[0]}
+
Render prop: {result.renderProp[0]}
+ + ); +}; + +storiesOf('useAdopt', module) + .add('Docs', () => ) + .add('Demo', () => + + ) diff --git a/src/index.ts b/src/index.ts index 6cbb5f6a..96c1f297 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ import createMemo from './createMemo'; +import useAdopt from './useAdopt'; import useAsync from './useAsync'; import useAudio from './useAudio'; import useBattery from './useBattery'; @@ -44,6 +45,7 @@ import useWindowSize from './useWindowSize'; export { createMemo, + useAdopt, useAsync, useAudio, useBattery, diff --git a/src/useAdopt.ts b/src/useAdopt.ts new file mode 100644 index 00000000..175c8c5c --- /dev/null +++ b/src/useAdopt.ts @@ -0,0 +1,19 @@ +import * as React from 'react'; +import useRenderProp from './useRenderProp'; + +const useAdopt = (map: {[key in keyof T]: React.ReactElement}): [React.ReactElement, T] => { + const keys = Object.keys(map); + const fragments: React.ReactElement[] = []; + const result: T = {} as T; + + keys.sort(); + for (const key of keys) { + const [fragment, value] = useRenderProp(map[key]); + fragments.push(React.cloneElement(fragment, {key})); + result[key] = value; + } + + return [React.createElement(React.Fragment, null, ...fragments), result]; +}; + +export default useAdopt;