Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Context API not working from custom NPM component library

I've built a ReactJS component library that I use for multiple projects installed via an NPM package using a sim link. I want to use the context API to pass data from a parent component served from the component library to my base project to be consumed by multiple consumer components also served from the component library. When I try the context is always undefined in my child components.

If I place my consumer component in my provider component within my library it works like a champ but this defeats what I'm trying to achieve. If I export both the provider and the consumer to my base project the consumer doesn't see the provider.

This is from my base project

import { Screen, COD, GenericSocketServer } from 'component-library'

export default class View extends React.PureComponent {
  render() {
    return (
      <Screen className="screen odmb1">
        <GenericSocketServer>
          <COD />
        </GenericSocketServer>
      </Screen>
    )
  }
}

This is my provider code exported from my 'component-library'

import React from 'react';
import MyContext from "./context";
import COD from './../cod';

export default class GenericSocketServer extends React.Component {
  render() {
    return (
      <MyContext.Provider value={{ foo: 'bar' }}>
        <COD />
        {this.props.children}
      </MyContext.Provider>
    );
  }
}

This is my content code used in 'component-library'

import React from 'react'
const MyContext = React.createContext()
export default MyContext

This is my consumer component exported from 'component-library'

import MyContext from "../GenericSocketServer/context"

class COD extends React.Component {
  render() {
    return (
      <React.Fragment>
        <MyContext.Consumer>
          {(context) => { 
            /*
               context comes back undefined 
               I expect { foo: 'bar' }
            */
            console.log('context :', context)
            return (
              <p>This should work</p>
          )}}
        </MyContext.Consumer>
      </React.Fragment>
    )
  }
}

Context always comes back undefined as if it doesn't see the parent provider. I think I'm ether doing something wrong initializing the context myself or for some reason the two components I'm importing just don't share the same context. Please help!! Not sure if I should give up on this and just use redux.

like image 648
Reedling78 Avatar asked Sep 17 '19 14:09

Reedling78


People also ask

What would happen if we didn’t use the react Context API?

If we didn’t use the React Context API, we would have needed to pass the state down to every component as props. In our example, it would have only been a slight annoyance to pass cities and addCity to the right components.

How to get the current context of a component in react?

const MyContext = React.createContext(defaultValue); Creates a Context object. When React renders a component that subscribes to this Context object it will read the current context value from the closest matching Provider above it in the tree.

What is provider in react context?

Every Context object comes with a Provider React component that allows consuming components to subscribe to context changes. The Provider component accepts a value prop to be passed to consuming components that are descendants of this Provider. One Provider can be connected to many consumers.

What is context in react legacy API?

Legacy API; When to Use Context . Context is designed to share data that can be considered “global” for a tree of React components, such as the current authenticated user, theme, or preferred language. For example, in the code below we manually thread through a “theme” prop in order to style the Button component:


1 Answers

Maybe you are making multiple instances of the component providing the context. Let's say you have a component Sound, which starts by:

    const { Provider, Consumer } = React.createContext();

If you import this library from your main project, the context will be created at the global space. You then use it to render your document tree. But in another component you also imported this library, which had to be resolved during webpack transpilation. It thus has its own copy of the above lines and a context object created in its own space. The problem occurs when you try to use the Consumer, because the Provider was only made by the main project for the first context object, and the second context's provider instance was never instantiated, thus returns undefined.

A solution to the problem is to enforce a single context object, which you can achieve by telling the second component's webpack that the provider-owning library is an external, so when webpack reaches e.g. the "import sound" line, it will not go further and will assume this dependency is resolved at runtime. When runtime comes, it will take it from the same place where the main project is taking it. To do this in webpack, e.g. for above "sound" library, add this to your other component (not main project):

{
   ...
   externals: {
      ...
      'sound': 'sound'
   }
   ...
}

Also in your component package.json:

{
   ...
   peerDependencies: {
     "sound": "^1.2.3"
   }
}
like image 104
Darko Maksimovic Avatar answered Oct 19 '22 22:10

Darko Maksimovic