From e0e68fbd3ca0579d9b94e5c95d8394c038ecc87a Mon Sep 17 00:00:00 2001 From: Erik Aybar Date: Thu, 8 Feb 2018 13:50:26 -0700 Subject: [PATCH 1/3] Add support for props.components as functions This enables passing the results of outer(s) to inner(s) for more advanced composition. Related issue https://github.com/jmeas/react-composer/issues/19 --- src/index.js | 12 ++++++++++-- test/index.test.js | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index 5c2cd46..f03f441 100644 --- a/src/index.js +++ b/src/index.js @@ -26,7 +26,13 @@ export default function Composer({ } const componentIndex = childrenComponents.length - 1; - const component = components[componentIndex]; + + const component = + // Each props.components entry is either an element or function [element factory] + // When it is a function, produce an element by invoking it with currently accumulated results. + typeof components[componentIndex] === 'function' + ? components[componentIndex](results) + : components[componentIndex]; // This is the index of where we should place the response within `results`. // It's not the same as `componentIndex` because we reversed the components when @@ -57,7 +63,9 @@ export default function Composer({ Composer.propTypes = { children: PropTypes.func, - components: PropTypes.array, + components: PropTypes.arrayOf( + PropTypes.oneOfType([PropTypes.element, PropTypes.func]) + ), renderPropName: PropTypes.string, mapResult: PropTypes.func }; diff --git a/test/index.test.js b/test/index.test.js index 121fe8c..0bdfb2a 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -2,6 +2,11 @@ import React from 'react'; import { shallow, mount } from 'enzyme'; import Composer from '../src'; +// Does nothing other than render so that its props may be inspected +function MyComponent(props) { + return
Inspect my props!
; +} + function Echo({ value, children }) { return children({ value }); } @@ -92,6 +97,41 @@ describe('React Composer', () => { }); }); + describe('Render, three components; elements and functions', () => { + test('It supports both elements and functions in props.components', () => { + const wrapper = mount( + , + + // A function [element factory] may be passed that is invoked with + // the currently accumulated results to produce an element. + ([outerResult]) => { + expect(outerResult).toEqual({ value: 'outer' }); + return ; + }, + + ([outerResult, middleResult]) => { + // Assert within element factory to avoid insane error messages for failed tests :) + expect(outerResult).toEqual({ value: 'outer' }); + expect(middleResult).toEqual({ value: 'outer + middle' }); + return ; + } + ]} + children={results => } + /> + ); + + expect(wrapper.find(Echo).length).toEqual(3); + expect(wrapper.find(MyComponent).prop('results')).toEqual([ + { value: 'outer' }, + { value: 'outer + middle' }, + { value: 'outer + middle + inner' } + ]); + }); + }); + describe('Render, one component; custom `renderPropName`', () => { test('It should render the expected result', () => { const mockChildren = jest.fn(([result]) =>
{result.value}
); From da31bffa051746e1ef0c05ea5b9090248b34bc7f Mon Sep 17 00:00:00 2001 From: Erik Aybar Date: Thu, 8 Feb 2018 14:00:39 -0700 Subject: [PATCH 2/3] Add props.components as function example to README --- README.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 90b2556..593e4db 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,25 @@ follows: ##### `components` -The render prop components to compose. +The render prop components to compose. This is an array of [React elements](https://reactjs.org/docs/glossary.html#elements) and/or functions that return elements given the currently accumulated results. + +```jsx +, + // A function may be passed that will be invoked with the currently accumulated results. + // Functions provided must return a valid React element. + ([outerResults]) => , + ([outerResults, middleResults]) => ( + + ) + ]}> + {([outerResults, middleResults, innerResults]) => { + /* ... */ + }} + +``` > Note: You do not need to specify the render prop on the components. If you do specify the render prop, it will > be ignored. From a96302db84661e0eb7f91fe4a23a5c8756d0d770 Mon Sep 17 00:00:00 2001 From: James Smith Date: Thu, 8 Feb 2018 16:03:16 -0800 Subject: [PATCH 3/3] 3.1.0 --- CHANGELOG.md | 12 ++++++++++-- package.json | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d136e9b..506dc45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,20 @@ # Changelog -### v3.0.1 (2018/1/3) +### v3.1.0 (2018/2/8) + +**New Features** + +* Within the `components` array, you may now specify a `function` that returns + a [React Element](https://reactjs.org/docs/glossary.html#elements). + The function will be called with the currently accumulated results. + +### v3.0.1 (2018/2/3) **Bug Fixes** * Ensures the array passed to the render prop is a new object each time -### v3.0.0 (2018/1/2) +### v3.0.0 (2018/2/3) React's new Context API has been finalized, and it uses functional `children` rather than a prop named `render`. Accordingly, this library has been updated to use `children` as the default. diff --git a/package.json b/package.json index e85597c..821b011 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-composer", - "version": "3.0.1", + "version": "3.1.0", "description": "Compose render prop components", "main": "lib/index.js", "module": "es/index.js",