{"id":13781299,"url":"https://github.com/troch/react-zap","last_synced_at":"2025-04-19T11:56:14.909Z","repository":{"id":57347903,"uuid":"135201377","full_name":"troch/react-zap","owner":"troch","description":":zap: Zap props from one React component to another, using React new context API and your existing higher-order components :zap:","archived":false,"fork":false,"pushed_at":"2018-07-03T11:29:49.000Z","size":177,"stargazers_count":17,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-20T18:46:49.015Z","etag":null,"topics":["context","higher-order-component","javascript","react"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/troch.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-05-28T19:30:04.000Z","updated_at":"2023-06-07T07:02:58.000Z","dependencies_parsed_at":"2022-08-28T01:40:29.621Z","dependency_job_id":null,"html_url":"https://github.com/troch/react-zap","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/troch%2Freact-zap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/troch%2Freact-zap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/troch%2Freact-zap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/troch%2Freact-zap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/troch","download_url":"https://codeload.github.com/troch/react-zap/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241421151,"owners_count":19960233,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["context","higher-order-component","javascript","react"],"created_at":"2024-08-03T18:01:24.677Z","updated_at":"2025-03-01T20:31:13.958Z","avatar_url":"https://github.com/troch.png","language":"TypeScript","funding_links":[],"categories":["List","Libraries"],"sub_categories":[],"readme":"[![npm version](https://badge.fury.io/js/react-zap.svg)](http://badge.fury.io/js/react-zap)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Build Status](https://travis-ci.org/troch/react-zap.svg)](https://travis-ci.org/troch/react-zap)\n[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier)\n\n# react-zap\n\n:zap: Zap props from one React component to another! :zap:\n\n## Why?\n\nReact's new context API allows you to send data from one component to any component in its tree of children. React-zap lets you tie this powerful new feature in to the similarly powerful concept of higher-order components!\n\n## HoCs _and_ Render Props?\n\nOne aspect of the new context API which has been much talked about in the community is that it uses the `function-as-a-child` pattern (also called `render props`) for its Consumers. This pattern has been positioned by some as an alternative to higher-order components, so the general impression is that you need to choose: either use HoCs or use Render Props.\n\nHowever, the API is about sharing dynamic context, not about render functions. The ability to pass data directly to any child is applicable to many situations; the method with which you access this data is not relevant to the feature. And in fact, this feature can be combined with higher-order components to make it even more powerful!\n\n**HoCs are not dead**! This package allows you to use your trusted and useful HoCs and to plug them into React's new context API.\n\nThis package offers two higher-order components: `propsToContext` to populate a context provider with existing props, and `contextToProps` if you prefer to consume context with a HoC (for example within a `compose` function).\n\n## API\n\n### :zap: `propsToContext(Provider, config?)(BaseComponent)`\n\nWraps your component with the specified `Provider`, and sends the component's props into context. By default, all props will be included in context; you can optionally define a list of props to include, or a function to map the props manually.\n\n*   `Provider`: a React context provider, returned by `React.createContext`\n*   `config`:\n    * An array of prop keys to sent to context.\n\n        Example: `propsToContext(Provider, ['propToInclude'])(Component)`\n\n    * A function mapping props to context.\n\n        Example: `propsToContext(Provider, ({ propToIgnore, ...otherProps }) =\u003e otherProps)(Component)`\n\n### :zap: `contextToProps(Consumer, config?)(BaseComponent)`\n\nWraps your component with the specified `Consumer`, and sends the context into its props. By default, the context will be spread into the component's props; you can optionally define a prop key for the context object, or a function to map to props manually.\n\n*   `Consumer`: a React context consumer, returned  by `React.createContext`\n*   `config` (optional):\n    * A string, to be used as a prop key for the context object.\n\n        Example: `contextToProps(Consumer, 'allContext')(Component)`\n\n    * A function mapping context to props.\n\n        Example: `contextToProps(Consumer, ({ contextToIgnore, ...otherContexts }) =\u003e otherContexts)(Component)`\n\n## Examples\n\n### With a state HOC\n\nUsing [react-state-hoc](troch/react-state-hoc). We will first create our context components:\n\n```js\nimport React from 'react'\n\nconst initialState = {\n    visible: false\n}\n\nconst {\n    Provider: StateProvider,\n    Consumer: StateConsumer\n} = React.createContext(initialState)\n\nexport { initialState, StateProvider, StateConsumer }\n```\n\nGiven an imaginary `ViewComponent`, we will set our state in context using `propsToContext`. Note the use of a `compose` function to compose our different higher-order components, provided by some libraries like `redux` ([you can write your own!](https://gist.github.com/JamieMason/172460a36a0eaef24233e6edb2706f83))\n\n```js\nimport React from 'react'\nimport { propsToContext } from 'react-zap'\nimport { withState } from 'react-state-hoc'\n\nimport { initialState, StateProvider } from './context'\nimport ViewComponent from './ViewComponent'\n\nexport default compose(\n    withState(initialState, {\n        setVisibility: visible =\u003e ({ visible })\n    })\n    propsToContext(StateProvider, [ 'visible', 'setVisibility' ])\n)(ViewComponent)\n```\n\nNow the state in `withState` will be added to our provider. Note that we have whitelisted props `'visible'` and `'setVisibility'`. To consume it, given `ToggleButton` and `Toggle` components mounted somewhere deep in `ViewComponent`:\n\n```js\nimport React from 'react'\nimport { contextToProps } from 'react-zap'\nimport { StateConsumer } from './context'\n\nconst withState = contextToProps(StateConsumer)\n\nconst ToggleButton = ({ setVisibility }) =\u003e (\n    \u003cbutton onClick={() =\u003e setVisibility(!visible)}\u003e\n        Toggle\n    \u003c/button\u003e\n)\n\nconst Toggle = ({ visible }) =\u003e visible ? \u003cdiv\u003eHello\u003c/div\u003e : null\n\nexport {\n    ToggleButton: withState(ToggleButton),\n    Toggle: withState(Toggle)\n}\n```\n\nWith render functions instead of `contextToProps` HoC:\n\n```js\nimport React from 'react'\nimport { StateConsumer } from './context'\n\nexport function ToggleButton() {\n    return (\n        \u003cStateConsumer\u003e\n            {({ visible, setVisibility }) =\u003e (\n                \u003cbutton onClick={() =\u003e setVisibility(!visible)}\u003eToggle\u003c/button\u003e\n            )}\n        \u003c/StateConsumer\u003e\n    )\n}\n\nexport function Toggle() {\n    return (\n        \u003cStateConsumer\u003e\n            {({ visible, setVisibility }) =\u003e\n                visible ? \u003cdiv\u003eHello\u003c/div\u003e : null\n            }\n        \u003c/StateConsumer\u003e\n    )\n}\n```\n\n### With redux `connect`\n\nThe same logic applies with a higher-order component like `connect` from the `react-redux` package:\n\n```js\nimport React from 'react'\nimport { propsToContext } from 'react-zap'\nimport { compose } from 'redux'\nimport { connect } from 'react-redux'\nimport ViewComponent from './ViewComponent'\nimport ViewChild from './ViewChild'\n\nconst { Provider, Consumer } = React.createContext()\n\n// Set context for any component in `ViewComponent`\n// All props received by `propsToContext` will be set to `Provider`,\n// including what is returned by `mapStateToProps` and `mapDispatchToProps`\nconst ViewContainer = compose(\n    connect(mapStateToProps, mapDispatchToProps),\n    propsToContext(Provider)\n)(ViewComponent)\n\n// No we can consume our context in any descendant!\nconst ViewChild = () =\u003e \u003cConsumer\u003e{context =\u003e \u003cdiv /\u003e}\u003c/Consumer\u003e\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftroch%2Freact-zap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftroch%2Freact-zap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftroch%2Freact-zap/lists"}