I've given up hope on getting mt head around Redux (I'm new to React), and see the Alpha version of React offers a new Context.
So I am attempting to learn it, and my goal is, I have a Navbar, which I want to respond to a state within my context, {isAuthorised: false}
.
I'm following this guys video:
But he has all is code in a single file. I'm trying to do it 'right'.
What I did was created a folder called 'context' and within that, created a jsx called provider.jsx.
import React, {Component} from 'react';
export default class MyProvider extends Component {
constructor(props) {
super(props);
this.state = {
isAuthenticated: false
}
}
render() {
const MyContext = React.createContext();
return(
<MyContext.Provider value="Test Text">
{this.props.children}
</MyContext.Provider>
)
}
}
https://github.com/CraigInBrisbane/ReactLearning/blob/master/src/context/provider.jsx
In there, I created the context within the render (This might be wrong... maybe that's meant to happen in my App jsx?).
I create a state in there, defaulting isAuthenticated to false. (I'll add code later to set that to what it should be).
This compiles... and runs.
In my App component, I use my provider like this:
import MyProvider from './context/provider.jsx';
export default class App extends Component {
render() {
return (
<MyProvider>
<div>
<Router>
<div>
<Navbar />
<Route exact path='/' component={Home} />
<Route path='/about' component={About} />
https://github.com/CraigInBrisbane/ReactLearning/blob/master/src/app.jsx
So I am wrapping all my code with MyProvider.
In my Navbar component, I import my provider:
import MyProvider from '../../context/provider.jsx';
I then try and output somethign from my provider within my render:
return (
<div>
<MyProvider.Consumer>
{(context)=> (
<p>Here I am {context}</p>
)}
</MyProvider.Consumer>
<nav className="navbar navbar-expand">
https://github.com/CraigInBrisbane/ReactLearning/blob/master/src/components/navbar/navbar.jsx
But this goes very badly for me.
Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Check the render method of
Navbar
. in Navbar (created by App) in div (created by App)
And
Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
How can I get this to work? Where should my .createContext reside?
Code (With error) is here.
React Context API provides first class support for class components. To use React Context, we use the Provider component to provide the shared data. In order to subscribe to the Context in class components, we use the contextType property of a class.
Consuming Context With Class-based ComponentsOne is to use the context from Consumer like “ThemeContext. Consumer” and the other method is by assigning context object from current Context to contextType property of our class. There is always a difference in how we want to use the Context.
To keep context re-rendering fast, React needs to make each context consumer a separate node in the tree. If two or more context values are often used together, you might want to consider creating your own render prop component that provides both.
We can pass in anything we want to the value prop of the context provider component. So sharing multiple states with one provider is no problem.
So the problem is that you export MyProvider
and try to access static component on it - which is undefined
:
console.log(MyProvider.Consumer); // undefined
the Consumer
is existing as a static property only in MyContext
component.
What you need to change:
provider.jsx
import React, {Component} from 'react';
export const MyContext = React.createContext();
export default class MyProvider extends Component {
constructor(props) {
super(props);
this.state = {
isAuthenticated: false
}
}
render() {
return(
<MyContext.Provider value={this.state.isAuthenticated}>
{this.props.children}
</MyContext.Provider>
)
}
}
then in navbar.jsx
import MyProvider, { MyContext } from '../../context/provider.jsx';
<MyProvider>
<MyContext.Consumer>
{(context)=> (
<p>Here I am {context}</p>
)}
</MyContext.Consumer>
</MyProvider>
take a look at this tutorial.
EDIT:
To have the Consumer
exist in MyProvider
you would have to assign static variable on it that points to MyContext Consumer
MyProvider.Consumer = MyContext.Consumer;
Then I think you could use it like:
<MyProvider>
<MyProvider.Consumer>
{(context)=> (
<p>Here I am {context}</p>
)}
</MyProvider.Consumer>
</MyProvider>
However I'm not sure if it is a good idea.
Was getting the same error...
Turns out I was using an older version of react-dom
. Updating it to ^16.3.0
fixed it for me!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With