Skip to content

pgarciacamou/react-context-consumer-hoc

Repository files navigation

react-context-consumer-hoc v2.x

React context consumer hoc. A 2KB lib that consumes context as props.

NPM JavaScript Style Guide Build Status Package Quality Renovate

Install

npm install --save react-context-consumer-hoc

Documentation

The Gist

Using withContextAsProps

import { withContextAsProps } from 'react-context-consumer-hoc'

// ContextA == { a: 1 } && ContextB == { b: 1 }
const InnerComponent = ({ a, b, ...ownProps }) => { /* ... */ }
const MyComponent = withContextAsProps(ContextA, ContextB)(InnerComponent)

Using withContext

import { withContext } from 'react-context-consumer-hoc'

// ContextA == { a: 1 } && ContextB == { b: 1 }
const InnerComponent = ({ c, ...ownProps }) => { /* ... */ }
const MyComponent = withContext(
  [ContextA, ContextB],
  (context, ownProps) => ({ c: context.a + context.b }) // mapContextToProps
)(InnerComponent)

Using withContext and reselect -> createSelector()

import { withContext } from 'react-context-consumer-hoc'
import { createSelector } from 'reselect'

const addAandB = createSelector(
  (context) => context.a,
  (context) => context.b,
  (a, b) => a + b
)

// ContextABC == { a: 1, b: 2, c: 3 }
const InnerComponent = ({ sum, ...ownProps }) => { /* ... */ }
const MyComponent = withContext(
  [ContextABC],
  (context, ownProps) => ({ sum: addAandB(context) }) // mapContextToProps
)(InnerComponent)

Namespaces using withContext and reselect -> createStructuredSelector()

import { withContext } from 'react-context-consumer-hoc'
import { createStructuredSelector } from 'reselect'

// ContextA == { a: 1 } && ContextB == { b: 1 }
const InnerComponent = ({ context: { a, b }, ...ownProps }) => { /* ... */ }
const MyComponent = withContext(
  [ContextA, ContextB],
  createStructuredSelector({
    context: createStructuredSelector({
      a: (context) => context.a,
      b: (context) => context.b
    })
  })
)(InnerComponent)

API

withContextAsProps

withContextAsProps(Context1[, Context2, ..., ContextN])(Component)

Wraps the Component with dynamically created consumers and passes all consumed context as props. withContextAsProps is a facade around withContext, providing a convenient API for the most common use cases.

Arguments

  • Context1[, Context2, ..., ContextN] (Comma-separated context list | required): At least 1 context API is needed. The component will be wrapped in consumers from each of the context passed to withContextAsProps.

    All react-context-consumer-hoc APIs wrap the new component once at export, i.e. there is no further computation done afterward.

    Note: in advanced scenarios where you need more control over the rendering performance, it is recommended to use withContext. In this case, you can pass a mapContextToProps function where you can specify which props from the context to select for a particular component instance. Most apps will not need this as long as the context doesn't change too often. One scenario could be if one of the context gets recomputed on every render but only a few really care about the changes.

withContext

withContext(contextList, mapContextToProps)(Component)

Wraps the Component with dynamically created consumers and passes all consumed context as props.

Arguments

  • contextList (Array | required): A list of context API with at least 1. The component will be wrapped in consumers from each of the context in the array.

  • mapContextToProps(context, ownProps): contextPropsObject (Function | required): This function is called with 2 arguments and must return an object conatining the props that will be passed to the component. The first argument is the consumed context from the APIs and the second argument is the props that are being passed to the component. mapContextToProps must return an object Note that this function is called on every render and the object returned will be destructured/passed as props to the component.

    Use reselect to efficiently compose selectors using memoization

Full example

// ProviderA.js
import React from 'react'
const childContextA = { a: 1 }
export const ContextA = React.createContext(childContextA)
export default ({ children }) => (
  <ContextA.Provider value={childContextA}>
    {children}
  </ContextA.Provider>
)

// ProviderB.js
import React from 'react'
const childContextB = { b: 2 }
export const ContextB = React.createContext(childContextB)
export default ({ children }) => (
  <ContextB.Provider value={childContextB}>
    {children}
  </ContextB.Provider>
)

// MyComponent.js
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { withContextAsProps } from 'react-context-consumer-hoc'
import { ContextA } from './ProviderA'
import { ContextB } from './ProviderB'

class MyComponent extends Component {
  static propTypes = {
    // from context
    a: PropTypes.number.isRequired,
    b: PropTypes.number.isRequired,

    // own props
    c: PropTypes.number.isRequired
  }

  render() {
    return (
      <div>
        <div>{this.props.a}</div>
        <div>{this.props.b}</div>
        <div>{this.props.c}</div>
      </div>
    )
  }
}

export default withContextAsProps(ContextA, ContextB)(MyComponent)

// App.js
import React, { Component } from 'react'
import ProviderA from './ProviderA'
import ProviderB from './ProviderB'
import MyComponent from './MyComponent'

export default class App extends Component {
  render () {
    return (
      <ProviderA>
        <ProviderB>
          <div className='stuff'>some other content</div>
          <div className='nested element'>
            <MyComponent c="3" />
          </div>
        </ProviderB>
      </ProviderA>
    )
  }
}

Author

Contributors

pablo garcia
pablo garcia
πŸ’» πŸ“– πŸ’‘

This project follows the all-contributors specification.

Package Quality