question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[feature-request] Expose custom context to hooks

See original GitHub issue

What is the current behavior?

The Provider component allows consumers to pass a custom context, but the current hooks API does not allow that custom context to be used.

What is the expected behavior?

I’d like to be able to access a custom context via React Redux hooks. I’d expect this would be implemented with a “hook factory” pattern for performance reasons, but that’s an implementation detail.

Which versions of React, ReactDOM/React Native, Redux, and React Redux are you using? Which browser and OS are affected by this issue? Did this work in previous versions of React Redux?

This issue is unique to the v7-hooks branch. I suppose you could say this has never worked in previous versions of React Redux, since hook support is new 🙂or, it might be argued that the HOC pattern was able to access alternate contexts, so hook support would be incomplete without it.

Note: I have a PR prepared; I didn’t read the contributing guidelines until after I’d written the code, which is why I’m doubling back and creating the discussion issue now.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:4
  • Comments:13 (12 by maintainers)

github_iconTop GitHub Comments

3reactions
ryaninventscommented, Jun 11, 2019

Good point! I was trying to avoid making assumptions about the consumer’s application, but ended up assuming all use cases would look like mine instead. 😅

I’ll put up a PR within the next few days using the create* API you’ve proposed.

1reaction
ryaninventscommented, Jun 11, 2019

I’ve got a branch with the following as a proposal:

createCustomHooks()

This utility function returns a set of hooks bound to a different context. You might use this to help manage a very complex reusable component, allowing it to coexist within a Redux application using its own store instance without colliding.

import React from 'react'
import { createCustomHooks, Provider } from 'react-redux'
import createComponentStore, { increment } from './component-store'

const customContext = React.createContext()
const customStore = createComponentStore()

const customHooks = createCustomHooks(customContext)

const Increment = () => {
  const dispatch = customHooks.useDispatch()
  return (
    <button onClick={() => dispatch(increment())}>+1</button>
  )
}

const InternalCount = () => {
  const count = customHooks.useSelector(s => s.count)
  return (
    <span>{String(count)}</span>
  )
}

export const ReusableCounterComponent = ({ children }) => {
  return (
    <Provider context={customContext} store={customStore}>
      <div>
        <Increment /> <InternalCount />
        {children}
      </div>
    </Provider>
  )
}

Note that consumers of your component will want any children to use the top-level application Store, not your Store. By creating a separate context, you will permit nested components to work as expected, instead of attaching to your component’s store.

createContextValue

This utility function allows you to use a singleton instance of your Redux store. This is useful in cases where your component will be reusable, but you want all instances to share the same store. For instance, this would be a great way to implement caching without requiring consumers of the component to wrap their application in a top-level <Provider>.

Note that if you create a context using this utility, you will only be able to access it through hooks created with createCustomHooks.

import { createCustomHooks, createContextValue } from 'react-redux'
import store from './store'

const customContext = React.createContext(createContextValue(store))
const customHooks = createCustomHooks(() => React.useContext(customContext))

export const Increment = () => {
  const dispatch = customHooks.useDispatch()
  return (
    <button onClick={() => dispatch(increment())}>+1</button>
  )
}

This is just one way we could expose it; my proposal branch is mostly clean code but there’s still room for improvement.

The key pieces are Subscription and useSelectorWithStoreAndSubscription (factored out from useSelector), so even if the only outcome of this request were to expose those two as exports, it would still permit custom contexts.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Using React context with a custom hook
Using React context with a custom hook. React Context is a great, builtin API for passing data from a parent component to any...
Read more >
Use Context and Custom Hooks to share user state ... - Fatma Ali
Use Context and Custom Hooks to share user state across your React App. The hooks and context API changed the way we build...
Read more >
How to Use Context API with Hooks While Avoiding Bottlenecks
Learn how to efficiently create and consume Context API with the use of hooks without performance issues.
Read more >
Webhooks and insecure internal web services - GitLab Docs
On the left sidebar, select Settings > Network. Expand Outbound requests. Select the Allow requests to the local network from web hooks and...
Read more >
aggrid react
Ag-Grid custom built framework components for ag-grid-react. ... To do this, we are going to use React's useImperativeHandle hook. destroy () to destroy...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found