useContext(Context) show warning on console in React Native - reactjs

I have use React Context API hook in react native. I created Consumer and Provider both to pass props and state from parent to child. Code is working perfectly fine, I have received props from parent to child.
I have received following warning on my console:-
Warning: Calling useContext(Context.Consumer) is not supported, may
cause bugs, and will be removed in a future major release. Did you
mean to call useContext(Context) instead?
Please check below added code:-
I have create common context file CommonContext.js.
import React, {createContext} from 'react';
const MyContext = createContext();
export const LoginProvider = MyContext.Provider;
export const LoginConsumer = MyContext.Consumer;
This is my provider code
import React, {PureComponent} from 'react';
import {View, Text} from 'react-native';
import {LoginProvider} from './CommonContext';
export default class Login extends PureComponent {
constructor(props) {
super(props);
}
render() {
return (
<View style={Styles.mainContainer}>
<LoginProvider value={this.props}>
<LoginScreenView />
</LoginProvider>
</View>
);
}
}
From this way i am access parent component data into child hook
import {LoginConsumer} from './CommonContext';
export default function LoginScreenView(props) {
let loginConsumer = useContext(LoginConsumer);
return (
<View style={Styles.mainContainer}>
<Text>{loginConsumer}</Text>
</View>
);
}

You are receiving this error because you are calling useContext on a Context.Consumer instance, instead of a Context.
You do like this:
export const LoginConsumer = MyContext.Consumer;
and then you call useContext on LoginConsumer:
let loginConsumer = useContext(LoginConsumer);
Instead, you should call useContext on MyContext, like this:
Export the context from CommonContext.js:
export const MyContext = createContext();
Import the context instead of the context consumer in the file where you're using it:
import { MyContext } from './CommonContext';
and then using it with useContext:
let login = useContext(MyContext);
So your second component that you posted would look like this:
import { MyContext } from './CommonContext';
export default function LoginScreenView(props) {
let login = useContext(MyContext);
return (
<View style={Styles.mainContainer}>
<Text>{login}</Text>
</View>
);
}

Related

UseContext can't find variable?

I'm trying to understand useContext but I don't see what I'm doing wrong here, I get the error message "Can't find variable: Test" but in the tutorial I'm reading from it never says anything about needing to import/export other than what is in the code?
Thank you!
App.js
import React, { createContext } from 'react';
const Test = createContext()
export default function App() {
return (
<Test.Provider value="hello">
<Home/>
</Test.Provider> );
}
Home.js
const Home = () => {
return(
<Test.Consumer>
<View style={styles.homeContainer}>
{value}
</View>
</Test.Consumer>
)
}
You aren't exporting Test from App.js, so you can't just implicitly use it in Home.js.
I'd recommend moving it to another file, say, contexts.js:
import React from 'react';
const Test = React.createContext();
export {Test};
You can then do
import {Test} from './contexts';
in both (or all, in the future) of your other source files to refer to the same context type.
I suggest you to create the context in a separate file :
test-context.js
import { createContext } from 'react';
export const TestContext = createContext();
App.js
import React from 'react';
import { TestContext } from './test-context';
export default function App() {
return (
<TestContext.Provider value="hello">
<Home/>
</TestContext.Provider>
);
}
In TestContext.Consumer, you must provide a function to consume the context value.
Home.js
import React from 'react';
import { TestContext } from './test-context';
export default const Home = () => {
return (
<TestContext.Consumer>
value => (
<View style={styles.homeContainer}>
{value}
</View>
)
</TestContext.Consumer>
)
}
We often forget about old school rules, when reading docs about fancy libraries these days.
In your example, Context is just a JS object, in order to access Test.Consumer, Test must be in scope of the file.
So, you have to import Test object (context) on order to access the Consumer property.

How to render a notification from a global function - React

I'm new to React and I am trying to utilize notistack for ReactJs and I would like to display the notification by calling a helper function but I'm not quite sure how to do that. Here is the standard code required to use the component:
App component:
import { SnackbarProvider } from 'notistack';
<SnackbarProvider maxSnack={3}>
<App />
</SnackbarProvider>
Component that displays the notification:
import { withSnackbar } from 'notistack';
class MyComponent extends Component {
handleNetworkRequest = () => {
fetchSomeData()
.then(() => this.props.enqueueSnackbar('Successfully fetched the data.'))
.catch(() => this.props.enqueueSnackbar('Failed fetching data.'));
};
render(){
//...
};
};
export default withSnackbar(MyComponent);
I would like to place the enqueueSnackbar('my notification message') inside a class or some kind of helper function so that I can call the helper function from anywhere in the react app to display a message without having to wrap the export of a component with withSnackbar(MyComponent);. How can this be done?
I would achieve this via Context API like so:
create a context object which holds the enqueueSnackbar function
Then pass it from the uppermost App comp or any other parent comp
Access it anywhere inside any child component and invoke it as needed
Some pseduo code:
// context.js
import React from 'react';
import { useSnackbar } from 'notistack';
const { enqueueSnackbar } = useSnackbar();
const snackbarContext = React.createContext({ enqueueSnackbar });
export default snackbarContext;
Then wrap a parent component in the tree with this context's provider like so:
//parent.js
import SnackbarContext from './context.js'
const App = () => {
return (
<SnackbarContext.Provider>
<SomeParentComponent />
</SnackbarContext.Provider>
);
}
Now it can be used inside a dummy child component like so:
// child.js
import React, {useContext} from 'react'
import SnackbarContext from './context.js'
const DummyChild = ()=>{
const {enqueueSnackbar} = useContext(SnackbarContext);
return (
<div>
<h1>Dummy Component with snackbar invocation</h1>
<button onClick={() => enqueueSnackbar('Wohoooo')}>Show Snackbar</button>
</div>
)
}

Use of multiple contexts of React Context API in a class component [duplicate]

Hi I'm trying to access multiple contexts in a component but I got success with only one context value from provider. there are two providers ListContext and `MappingContext. How can I access contexts like this:
class TableData extends React.Component {
static contextType = ListContext;
static contextType = MappingContext;
componentDidMount() {
const data = this.context // it will have only one context from ListContext
}
I know I can use multiple providers in render() but I want to access the contexts like above. Any help will be appreciated.
Thanks
One workaround is to use a wrapper that combines the two contexts into one and then export the wrapper. There are multiple ways to implement the wrapper, but here is one:
Contexts.js
import React from "react";
export const Context1 = React.createContext("1");
export const Context2 = React.createContext("2");
export const ContextCombined1And2 = React.createContext("3");
ProvideCombinedContext.js
import React from "react";
import { Context1, Context2, ContextCombined1And2 } from "./Contexts";
// This is a reusable piece that could be used by any component that requires both contexts.
const ProvideCombinedContext = props => {
return (
<Context1.Consumer>
{context1 => (
<Context2.Consumer>
{context2 => (
<ContextCombined1And2.Provider value={{ context1, context2 }}>
{props.children}
</ContextCombined1And2.Provider>
)}
</Context2.Consumer>
)}
</Context1.Consumer>
);
};
export default ProvideCombinedContext;
Need2Contexts.js
import React from "react";
import { ContextCombined1And2 } from "./Contexts";
import ProvideCombinedContext from "./ProvideCombinedContext";
class Need2Contexts extends React.Component {
static contextType = ContextCombined1And2;
componentDidMount() {
console.log("Context=" + JSON.stringify(this.context));
}
render() {
return "this.context=" + JSON.stringify(this.context);
}
}
const WrappedNeed2Contexts = props => {
return (
<ProvideCombinedContext>
<Need2Contexts {...props} />
</ProvideCombinedContext>
);
};
export default WrappedNeed2Contexts;
index.js
import React from "react";
import ReactDOM from "react-dom";
import { Context1, Context2 } from "./Contexts";
import Need2Contexts from "./Need2Contexts";
function App() {
return (
<div className="App">
<Context1.Provider value="value1">
<Context2.Provider value="value2">
<Need2Contexts />
</Context2.Provider>
</Context1.Provider>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
You can see this in action and play with it here:
This is explained in the React context documentation:
You can only subscribe to a single context using this API. If you need to read more than one see Consuming Multiple Contexts.

Simple passing of Value from one Component to another through context

I'm new to react native and would like to use Context to keep a socket connection alive between screens in the future. For now, I tried to learn the concept of context just to pass simple values around but the value doesn't get sent.
Tried to follow the tutorial here, but by sending simple values instead.
I create my ValueContext in ValueContext.js here.
import React from 'react';
const ValueContext = React.createContext();
export default ValueContext;
Here's my LoginScreen.js where I set context provider.
import React, { Component } from 'react';
import ConnectionScreen from './ConnectionScreen';
import ValueContext from './ValueContext';
const testValue = 5;
export const sendValue = props => (
<ValueContext.Provider value={testValue}>
<ConnectionScreen />
</ValueContext.Provider>
)
class LoginScreen extends Component {
render() {
return()
}
}
Then in my ConnectionScreen.js
import React, { Component } from 'react';
import { View, Alert } from 'react-native';
import LoginScreen from './LoginScreen';
import ValueContext from './ValueContext';
export const receiveValue = props => (
<ValueContext.Consumer>
{testValue => <ConnectionScreen {...props} testValue={testValue} />}
</ValueContext.Consumer>
)
class ConnectionScreen extends Component {
showAlertValue = () => {
Alert.alert(this.props.testValue);
}
render() {
return(
<View>
{this.showAlertValue()}
</View>
)
}
}
So after setting the value in LoginScreen, I would like to access it in ConnectionScreen. All I get in my alert box is an empty box with no values. Am I doing something wrong here?

Context data does not get passed into nested component: React+Typescript+ContextAPI

I am using context API to avoid prop drilling across the components. I have a component which has two popup modal's(components). When I am trying to fetch the context data within Enclosing component data, but within the modal I would not get. If I pass again pass this context data as a props to these modal's and then if I fetch this props accessor then I am able to fetch. Where am I going wrong? If I am not wrong, this context API does not depend on the nested levels, can someone help me here?
CacheContext.tsx
import React from "react";
const context = React.createContext(null);
export default context;
ContextProvider.tsx
import React, {Component} from "react";
import context from './CacheContext';
var TinyCache = require( 'tinycache' );
var cache = new TinyCache();
class ContextProvider extends Component {
render() {
return (
<context.Provider value={cache}>
{this.props.children}
</context.Provider>
);
}
}
export default ContextProvider;
ComponentA.tsx
import * as React from "react";
import context from "../Utilities/CacheContext";
export default class ComponentA extends React.Component<{}, {}> {
componentDidMount() {
console.log(this.context) // I am able to the data here
}
render(){
return(
<Modal1/> //if I pass this as context={this.context} then it works
<Modal2/>
)
}
}
ComponentA.contextType=context;
Modal1.tsx
import * as React from "react";
import context from "../Utilities/CacheContext";
export default class Modal1 extends React.Component<{}, {}> {
componentDidMount() {
console.log(this.context) // I am unable able to the data here , If I use this.props.context and pass the context as props then I am able to get
}
render(){
return(
//some content
)
}
}
Modal1.contextType=context;
In the new context API ( https://reactjs.org/docs/context.html#api ) You should use the context.Consumer component using a function as children:
<context.Consumer>
{cache => console.log(cache)}
</context.Consumer>
If you need the cache in componentDidMount, pass the cache to a sub-component like this:
// render:
<context.Consumer>
{cache => <SubComponent cache={cache}/>}
</context.Consumer>
// SubComponent:
class SubComponent {
componentDidMount() {
console.log(this.props.cache);
}
}

Resources