Repository: acdlite/recompose Branch: master Commit: 3db12ce7121a Files: 170 Total size: 211.5 KB Directory structure: gitextract_7mr7594c/ ├── .codeclimate.yml ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .flowconfig ├── .gitignore ├── .npmignore ├── .prettierignore ├── .prettierrc ├── .size-snapshot.json ├── .travis.yml ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── babel.config.js ├── docs/ │ ├── API.md │ ├── flow.md │ └── performance.md ├── package.json ├── scripts/ │ ├── getPackageNames.js │ ├── installNestedPackageDeps.js │ ├── jest.setup.js │ ├── release.js │ └── rollup.config.js ├── src/ │ ├── basePackage.json │ └── packages/ │ ├── recompose/ │ │ ├── .npmignore │ │ ├── README.md │ │ ├── VERSION │ │ ├── __tests__/ │ │ │ ├── branch-test.js │ │ │ ├── componentFromProp-test.js │ │ │ ├── componentFromStream-test.js │ │ │ ├── componentFromStreamWithConfig-test.js │ │ │ ├── compose-test.js │ │ │ ├── createEventHandler-test.js │ │ │ ├── createSink-test.js │ │ │ ├── defaultProps-test.js │ │ │ ├── fixtures/ │ │ │ │ └── treeshake-entry.js │ │ │ ├── flattenProp-test.js │ │ │ ├── fromRenderProps-test.js │ │ │ ├── getContext-test.js │ │ │ ├── getDisplayName-test.js │ │ │ ├── hoistStatics-test.js │ │ │ ├── isClassComponent-test.js │ │ │ ├── lifecycle-test.js │ │ │ ├── mapProps-test.js │ │ │ ├── mapPropsStream-test.js │ │ │ ├── mapPropsStreamWithConfig-test.js │ │ │ ├── nest-test.js │ │ │ ├── onlyUpdateForKeys-test.js │ │ │ ├── onlyUpdateForPropTypes-test.js │ │ │ ├── pure-test.js │ │ │ ├── renameProp-test.js │ │ │ ├── renameProps-test.js │ │ │ ├── renderComponent-test.js │ │ │ ├── renderNothing-test.js │ │ │ ├── setDisplayName-test.js │ │ │ ├── setObservableConfig-test.js │ │ │ ├── setPropTypes-test.js │ │ │ ├── setStatic-test.js │ │ │ ├── shallowEqual-test.js │ │ │ ├── shouldUpdate-test.js │ │ │ ├── toClass-test.js │ │ │ ├── toRenderProps-test.js │ │ │ ├── types/ │ │ │ │ ├── test_branch.js │ │ │ │ ├── test_classBasedEnhancer.js │ │ │ │ ├── test_componentFromStream.js │ │ │ │ ├── test_createEventHandler.js │ │ │ │ ├── test_defaultProps.js │ │ │ │ ├── test_fromRenderProps.js │ │ │ │ ├── test_functionalEnhancer.js │ │ │ │ ├── test_getContext.js │ │ │ │ ├── test_mapProps.js │ │ │ │ ├── test_mapPropsStream.js │ │ │ │ ├── test_onlyUpdateForKeys.js │ │ │ │ ├── test_onlyUpdateForPropTypes.js │ │ │ │ ├── test_pure.js │ │ │ │ ├── test_shouldUpdate.js │ │ │ │ ├── test_statics.js │ │ │ │ ├── test_toClass.js │ │ │ │ ├── test_toRenderProps.js │ │ │ │ ├── test_utils.js │ │ │ │ ├── test_voodoo.js │ │ │ │ ├── test_withContext.js │ │ │ │ ├── test_withHandlers.js │ │ │ │ ├── test_withProps.js │ │ │ │ ├── test_withPropsOnChange.js │ │ │ │ └── test_withStateHandlers.js │ │ │ ├── utils.js │ │ │ ├── withContext-test.js │ │ │ ├── withHandlers-test.js │ │ │ ├── withProps-test.js │ │ │ ├── withPropsOnChange-test.js │ │ │ ├── withReducer-test.js │ │ │ ├── withState-test.js │ │ │ ├── withStateHandlers-test.js │ │ │ └── wrapDisplayName-test.js │ │ ├── baconObservableConfig.js │ │ ├── branch.js │ │ ├── componentFromProp.js │ │ ├── componentFromStream.js │ │ ├── compose.js │ │ ├── createEventHandler.js │ │ ├── createSink.js │ │ ├── defaultProps.js │ │ ├── flattenProp.js │ │ ├── flydObservableConfig.js │ │ ├── fromRenderProps.js │ │ ├── getContext.js │ │ ├── getDisplayName.js │ │ ├── hoistStatics.js │ │ ├── index.js │ │ ├── index.js.flow │ │ ├── isClassComponent.js │ │ ├── kefirObservableConfig.js │ │ ├── lifecycle.js │ │ ├── mapProps.js │ │ ├── mapPropsStream.js │ │ ├── mostObservableConfig.js │ │ ├── nest.js │ │ ├── onlyUpdateForKeys.js │ │ ├── onlyUpdateForPropTypes.js │ │ ├── package.json │ │ ├── pure.js │ │ ├── renameProp.js │ │ ├── renameProps.js │ │ ├── renderComponent.js │ │ ├── renderNothing.js │ │ ├── rxjs4ObservableConfig.js │ │ ├── rxjsObservableConfig.js │ │ ├── setDisplayName.js │ │ ├── setObservableConfig.js │ │ ├── setPropTypes.js │ │ ├── setStatic.js │ │ ├── shallowEqual.js │ │ ├── shouldUpdate.js │ │ ├── toClass.js │ │ ├── toRenderProps.js │ │ ├── utils/ │ │ │ ├── mapValues.js │ │ │ ├── omit.js │ │ │ └── pick.js │ │ ├── withContext.js │ │ ├── withHandlers.js │ │ ├── withProps.js │ │ ├── withPropsOnChange.js │ │ ├── withReducer.js │ │ ├── withState.js │ │ ├── withStateHandlers.js │ │ ├── wrapDisplayName.js │ │ └── xstreamObservableConfig.js │ └── recompose-relay/ │ ├── .npmignore │ ├── README.md │ ├── VERSION │ ├── createContainer.js │ ├── index.js │ └── package.json └── types/ ├── README.md └── flow-example/ ├── .eslintrc ├── .flowconfig ├── .gitignore ├── README.md ├── flow-typed/ │ ├── glamor.js │ └── react-motion.js ├── package.json ├── public/ │ ├── index.html │ └── manifest.json └── src/ ├── App.js ├── Item.js ├── ItemsAnimator.js ├── MouseDetector.js └── index.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .codeclimate.yml ================================================ --- engines: duplication: enabled: true config: languages: - javascript eslint: enabled: true fixme: enabled: true ratings: paths: - "**.js" exclude_paths: - "**/*-test.js" ================================================ FILE: .editorconfig ================================================ # editorconfig.org root = true [*] indent_style = space indent_size = 2 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [*.md] trim_trailing_whitespace = false [Makefile] indent_style = tab ================================================ FILE: .eslintignore ================================================ **/node_modules **/types ================================================ FILE: .eslintrc ================================================ { "extends": [ "eslint-config-airbnb", "prettier", "prettier/flowtype", "prettier/react" ], "plugins": [ "prettier" ], "parser": "babel-eslint", "env": { "browser": true, "node": true, "jest": true }, "globals": { "sinon": true }, "rules": { "semi": [2, "never"], "no-use-before-define": ["error", { "functions": false }], "no-unused-vars": ["error", { "argsIgnorePattern": "^_" }], "no-underscore-dangle": [0], "no-confusing-arrow": [0], "no-class-assign": [0], "no-plusplus": [0], "no-prototype-builtins": [0], "no-return-assign": [0], "max-len": ["error", { "code": 120, "ignorePattern": "^test", "ignoreUrls": true }], "lines-between-class-members": [0], "prefer-destructuring": [0], "import/no-unresolved": [0], "import/no-extraneous-dependencies": [0], "import/extensions": [0], "import/prefer-default-export": [0], "import/no-useless-path-segments": [0], "jsx-a11y/label-has-for": [0], "react/forbid-prop-types": [0], "react/prop-types": [0], "react/prefer-stateless-function": [0], "react/no-multi-comp": [0], "react/sort-comp": [0], "react/jsx-filename-extension": [0], "prettier/prettier": ["error", {"semi": false, "trailingComma": "es5", "singleQuote": true}], "react/destructuring-assignment": [0], "react/jsx-curly-brace-presence": [0], "react/no-unused-prop-types": [0], "react/require-default-props": [0], "react/button-has-type": [0] } } ================================================ FILE: .flowconfig ================================================ [ignore] /types/.* [include] [libs] [options] suppress_comment=\\(.\\|\n\\)*\\$ExpectError [lints] ================================================ FILE: .gitignore ================================================ node_modules release lib coverage .vscode yarn-error.log ================================================ FILE: .npmignore ================================================ /**/__tests__ coverage types ================================================ FILE: .prettierignore ================================================ node_modules package.json ================================================ FILE: .prettierrc ================================================ semi: false singleQuote: true trailingComma: es5 ================================================ FILE: .size-snapshot.json ================================================ { "lib/packages/recompose/dist/Recompose.umd.js": { "bundled": 46425, "minified": 16484, "gzipped": 4625 }, "lib/packages/recompose/dist/Recompose.min.js": { "bundled": 42863, "minified": 15204, "gzipped": 4194 }, "lib/packages/recompose/dist/Recompose.esm.js": { "bundled": 32428, "minified": 15083, "gzipped": 3550, "treeshaked": { "rollup": { "code": 310, "import_statements": 310 }, "webpack": { "code": 1838 } } } } ================================================ FILE: .travis.yml ================================================ language: node_js node_js: - "node" install: "yarn install --ignore-engines" before_script: "npm install -g codeclimate-test-reporter" script: - yarn run lint - yarn test after_script: - "CODECLIMATE_REPO_TOKEN=27125df6192d300baf67cd5f5eab6597c998256f4883b744a1055d0f0c18e608 codeclimate-test-reporter < coverage/lcov.info" - "cat ./coverage/lcov.info | $(npm bin)/codecov" ================================================ FILE: CHANGELOG.md ================================================ We are using the [Github Releases page](https://github.com/acdlite/recompose/releases) as our CHANGELOG. ================================================ FILE: LICENSE.md ================================================ The MIT License (MIT) Copyright (c) 2015-2018 Andrew Clark Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ ## A Note from the Author (acdlite, Oct 25 2018): Hi! I created Recompose about three years ago. About a year after that, I joined the React team. Today, we announced a proposal for [*Hooks*](https://reactjs.org/hooks). Hooks solves all the problems I attempted to address with Recompose three years ago, and more on top of that. I will be discontinuing active maintenance of this package (excluding perhaps bugfixes or patches for compatibility with future React releases), and recommending that people use Hooks instead. **Your existing code with Recompose will still work**, just don't expect any new features. Thank you so, so much to [@wuct](https://github.com/wuct) and [@istarkov](https://github.com/istarkov) for their heroic work maintaining Recompose over the last few years. Read more discussion about this decision [here](https://github.com/acdlite/recompose/issues/756#issuecomment-438674573). *** Recompose ----- [![build status](https://img.shields.io/travis/acdlite/recompose/master.svg?style=flat-square)](https://travis-ci.org/acdlite/recompose) [![coverage](https://img.shields.io/codecov/c/github/acdlite/recompose.svg?style=flat-square)](https://codecov.io/github/acdlite/recompose) [![code climate](https://img.shields.io/codeclimate/github/acdlite/recompose.svg?style=flat-square)](https://codeclimate.com/github/acdlite/recompose) [![npm version](https://img.shields.io/npm/v/recompose.svg?style=flat-square)](https://www.npmjs.com/package/recompose) [![npm downloads](https://img.shields.io/npm/dm/recompose.svg?style=flat-square)](https://www.npmjs.com/package/recompose) Recompose is a React utility belt for function components and higher-order components. Think of it like lodash for React. [**Full API documentation**](docs/API.md) - Learn about each helper [**Recompose Base Fiddle**](https://jsfiddle.net/evenchange4/p3vsmrvo/1599/) - Easy way to dive in ``` npm install recompose --save ``` **📺 Watch Andrew's [talk on Recompose at React Europe](https://www.youtube.com/watch?v=zD_judE-bXk).** *(Note: Performance optimizations he speaks about have been removed, more info [here](https://github.com/acdlite/recompose/releases/tag/v0.26.0))* ### Related modules [**recompose-relay**](src/packages/recompose-relay) — Recompose helpers for Relay ## You can use Recompose to... ### ...lift state into functional wrappers Helpers like `withState()` and `withReducer()` provide a nicer way to express state updates: ```js const enhance = withState('counter', 'setCounter', 0) const Counter = enhance(({ counter, setCounter }) =>
Count: {counter}
) ``` Or with a Redux-style reducer: ```js const counterReducer = (count, action) => { switch (action.type) { case INCREMENT: return count + 1 case DECREMENT: return count - 1 default: return count } } const enhance = withReducer('counter', 'dispatch', counterReducer, 0) const Counter = enhance(({ counter, dispatch }) =>
Count: {counter}
) ``` ### ...perform the most common React patterns Helpers like `componentFromProp()` and `withContext()` encapsulate common React patterns into a simple functional interface: ```js const enhance = defaultProps({ component: 'button' }) const Button = enhance(componentFromProp('component')) ) ``` ### `withReducer()` ```js withReducer( stateName: string, dispatchName: string, reducer: (state: S, action: A) => S, initialState: S | (ownerProps: Object) => S ): HigherOrderComponent ``` Similar to `withState()`, but state updates are applied using a reducer function. A reducer is a function that receives a state and an action, and returns a new state. Passes two additional props to the base component: a state value, and a dispatch method. The dispatch method has the following signature: ```js dispatch(action: Object, ?callback: Function): void ``` It sends an action to the reducer, after which the new state is applied. It also accepts an optional second parameter, a callback function with the new state as its only argument. ### `branch()` ```js branch( test: (props: Object) => boolean, left: HigherOrderComponent, right: ?HigherOrderComponent ): HigherOrderComponent ``` Accepts a test function and two higher-order components. The test function is passed the props from the owner. If it returns true, the `left` higher-order component is applied to `BaseComponent`; otherwise, the `right` higher-order component is applied. If the `right` is not supplied, it will by default render the wrapped component. ### `renderComponent()` ```js renderComponent( Component: ReactClass | ReactFunctionalComponent | string ): HigherOrderComponent ``` Takes a component and returns a higher-order component version of that component. This is useful in combination with another helper that expects a higher-order component, like `branch()`: ```js // `isLoading()` is a function that returns whether or not the component // is in a loading state const spinnerWhileLoading = isLoading => branch( isLoading, renderComponent(Spinner) // `Spinner` is a React component ) // Now use the `spinnerWhileLoading()` helper to add a loading spinner to any // base component const enhance = spinnerWhileLoading( props => !(props.title && props.author && props.content) ) const Post = enhance(({ title, author, content }) =>

{title}

By {author.name}

{content}
) ``` ### `renderNothing()` ```js renderNothing: HigherOrderComponent ``` A higher-order component that always renders `null`. This is useful in combination with another helper that expects a higher-order component, like `branch()`: ```js // `hasNoData()` is a function that returns true if the component has // no data const hideIfNoData = hasNoData => branch( hasNoData, renderNothing ) // Now use the `hideIfNoData()` helper to hide any base component const enhance = hideIfNoData( props => !(props.title && props.author && props.content) ) const Post = enhance(({ title, author, content }) =>

{title}

By {author.name}

{content}
) ``` ### `shouldUpdate()` ```js shouldUpdate( test: (props: Object, nextProps: Object) => boolean ): HigherOrderComponent ``` Higher-order component version of [`shouldComponentUpdate()`](https://facebook.github.io/react/docs/react-component.html#shouldcomponentupdate). The test function accepts both the current props and the next props. ### `pure()` ```js pure: HigherOrderComponent ``` Prevents the component from updating unless a prop has changed. Uses `shallowEqual()` to test for changes. ### `onlyUpdateForKeys()` ```js onlyUpdateForKeys( propKeys: Array ): HigherOrderComponent ``` Prevents the component from updating unless a prop corresponding to one of the given keys has updated. Uses `shallowEqual()` to test for changes. This is a much better optimization than the popular approach of using PureRenderMixin, `shouldPureComponentUpdate()`, or Recompose's own `pure()` helper, because those tools compare *every* prop, whereas `onlyUpdateForKeys()` only cares about the props that you specify. Example: ```js /** * If the owner passes unnecessary props (say, an array of comments), it will * not lead to wasted render cycles. * * Goes well with destructuring because it's clear which props the component * actually cares about. */ const enhance = onlyUpdateForKeys(['title', 'content', 'author']) const Post = enhance(({ title, content, author }) =>

{title}

By {author.name}

{content}
) ``` ### `onlyUpdateForPropTypes()` ```js onlyUpdateForPropTypes: HigherOrderComponent ``` Works like `onlyUpdateForKeys()`, but prop keys are inferred from the `propTypes` of the base component. Useful in conjunction with `setPropTypes()`. If the base component does not have any `propTypes`, the component will never receive any updates. This probably isn't the expected behavior, so a warning is printed to the console. ```js import PropTypes from 'prop-types'; // You need to import prop-types. See https://facebook.github.io/react/docs/typechecking-with-proptypes.html const enhance = compose( onlyUpdateForPropTypes, setPropTypes({ title: PropTypes.string.isRequired, content: PropTypes.string.isRequired, author: PropTypes.object.isRequired }) ) const Post = enhance(({ title, content, author }) =>

{title}

By {author.name}

{content}
) ``` ### `withContext()` ```js withContext( childContextTypes: Object, getChildContext: (props: Object) => Object ): HigherOrderComponent ``` Provides context to the component's children. `childContextTypes` is an object of React prop types. `getChildContext()` is a function that returns the child context. Use along with `getContext()`. ### `getContext()` ```js getContext( contextTypes: Object ): HigherOrderComponent ``` Gets values from context and passes them along as props. Use along with `withContext()`. ### `lifecycle()` ```js lifecycle( spec: Object, ): HigherOrderComponent ``` A higher-order component version of [`React.Component()`](https://facebook.github.io/react/docs/react-api.html#react.component). It supports the entire `Component` API, except the `render()` method, which is implemented by default (and overridden if specified; an error will be logged to the console). You should use this helper as an escape hatch, in case you need to access component lifecycle methods. Any state changes made in a lifecycle method, by using `setState`, will be propagated to the wrapped component as props. Example: ```js const PostsList = ({ posts }) => (
    {posts.map(p =>
  • {p.title}
  • )}
) const PostsListWithData = lifecycle({ componentDidMount() { fetchPosts().then(posts => { this.setState({ posts }); }) } })(PostsList); ``` ### `toClass()` ```js toClass: HigherOrderComponent ``` Takes a function component and wraps it in a class. This can be used as a fallback for libraries that need to add a ref to a component, like Relay. If the base component is already a class, it returns the given component. ### `toRenderProps()` ```js toRenderProps( hoc: HigherOrderComponent ): ReactFunctionalComponent ``` Creates a component that accepts a function as a children with the high-order component applied to it. Example: ```js const enhance = withProps(({ foo }) => ({ fooPlusOne: foo + 1 })) const Enhanced = toRenderProps(enhance) {({ fooPlusOne }) =>

{fooPlusOne}

}
// renders

2

``` ### `fromRenderProps()` ```js fromRenderProps( RenderPropsComponent: ReactClass | ReactFunctionalComponent, propsMapper: (...props: any[]) => Object, renderPropName?: string ): HigherOrderComponent ``` Takes a **render props** component and a function that maps props to a new collection of props that are passed to the base component. The default value of third parameter (`renderPropName`) is `children`. You can use any prop (e.g., `render`) for render props component to work. > Check the official documents [Render Props](https://reactjs.org/docs/render-props.html#using-props-other-than-render) for more details. ```js import { fromRenderProps } from 'recompose'; const { Consumer: ThemeConsumer } = React.createContext({ theme: 'dark' }); const { Consumer: I18NConsumer } = React.createContext({ i18n: 'en' }); const RenderPropsComponent = ({ render, value }) => render({ value: 1 }); const EnhancedApp = compose( // Context (Function as Child Components) fromRenderProps(ThemeConsumer, ({ theme }) => ({ theme })), fromRenderProps(I18NConsumer, ({ i18n }) => ({ locale: i18n })), // Render props fromRenderProps(RenderPropsComponent, ({ value }) => ({ value }), 'render'), )(App); // Same as const EnhancedApp = () => ( {({ theme }) => ( {({ i18n }) => ( ( )} /> )} )} ) ``` ## Static property helpers These functions look like higher-order component helpers — they are curried and component-last. However, rather than returning a new component, they mutate the base component by setting or overriding a static property. ### `setStatic()` ```js setStatic( key: string, value: any ): HigherOrderComponent ``` Assigns a value to a static property on the base component. ### `setPropTypes()` ```js setPropTypes( propTypes: Object ): HigherOrderComponent ``` Assigns to the `propTypes` property on the base component. ### `setDisplayName()` ```js setDisplayName( displayName: string ): HigherOrderComponent ``` Assigns to the `displayName` property on the base component. ## Utilities Recompose also includes some additional helpers that aren't higher-order components, but are still useful. ### `compose()` ```js compose(...functions: Array): Function ``` Use to compose multiple higher-order components into a single higher-order component. This works exactly like the function of the same name in Redux, or lodash's `flowRight()`. ### `getDisplayName()` ```js getDisplayName( component: ReactClass | ReactFunctionalComponent ): string ``` Returns the display name of a React component. Falls back to `'Component'`. ### `wrapDisplayName()` ```js wrapDisplayName( component: ReactClass | ReactFunctionalComponent, wrapperName: string ): string ``` Returns a wrapped version of a React component's display name. For instance, if the display name of `component` is `'Post'`, and `wrapperName` is `'mapProps'`, the return value is `'mapProps(Post)'`. Most Recompose higher-order components use `wrapDisplayName()`. ### `shallowEqual()` ```js shallowEqual(a: Object, b: Object): boolean ``` Returns true if objects are shallowly equal. ### `isClassComponent()` ```js isClassComponent(value: any): boolean ``` Returns true if the given value is a React component class. ### `createSink()` ```js createSink(callback: (props: Object) => void): ReactClass ``` Creates a component that renders nothing (null) but calls a callback when receiving new props. ### `componentFromProp()` ```js componentFromProp(propName: string): ReactFunctionalComponent ``` Creates a component that accepts a component as a prop and renders it with the remaining props. Example: ```js const enhance = defaultProps({ component: 'button' }) const Button = enhance(componentFromProp('component'))