I'm trying to context api in my ract-native app. But i'm getting this error.
TypeError: TypeError: Cannot read property 'number' of undefined. What is wrong my code?
appContext.js
import React from 'react';
export const AppContext = React.createContext();
class AppProvider extends React.Component {
constructor(props) {
super(props);
this.state = {
number: 10,
};
}
render() {
return
(
<AppContext.Provider value={this.state}>
{this.props.children}
</AppContext.Provider>
)
}
}
export default AppProvider;
homeScreen.js
import { AppContext } from './appContext';
<AppContext.Consumer>
{(context) => context.number}
</AppContext.Consumer>
This is because you are not using your AppProvider component anywhere in your App. Try like this:
const AppContext = React.createContext();
class AppProvider extends React.Component {
constructor( props ) {
super( props );
this.state = {
number: 10,
};
}
render() {
return (
<AppContext.Provider value={this.state}>
{this.props.children}
</AppContext.Provider>
);
}
}
class App extends React.Component {
render() {
return (
<AppProvider>
<AppContext.Consumer>
{context => context.number}
</AppContext.Consumer>
</AppProvider>
);
}
}
AppProvider is merely a standard component here. It renders the context's Provider and that one gets some children. So, you should use this AppProvider component somewhere in your app and pass a child with a Consumer.
If you want to keep your context in a separate file it would be like this:
Context and provider component
import React from "react";
export const AppContext = React.createContext();
class AppProvider extends React.Component {
constructor( props ) {
super( props );
this.state = {
number: 1745,
};
}
render() {
return (
<AppContext.Provider value={this.state}>
{this.props.children}
</AppContext.Provider>
);
}
}
export default AppProvider;
Main component
import React from "react";
import AppProvider, { AppContext } from "./AppProvider";
class App extends React.Component {
render() {
return (
<AppProvider>
<AppContext.Consumer>
{context => context.number}
</AppContext.Consumer>
</AppProvider>
);
}
}
export default App;
Related
Why Context value showing undefined?
src/Context.js:
import React, { Component } from 'react';
const Context = React.createContext();
export class Provider extends Component {
state = { a: 1, b: 2 };
render() {
return (
<Context.Provider value={this.state}>
{this.props.children}
</Context.Provider>
);
}
}
export const Consumer = Context.Consumer;
src/country/CountryList.js:
import React, { Component } from 'react';
import { Consumer } from '../../Context';
class CountryList extends Component {
render() {
return (
<Consumer>
{value => {
console.log('val:' + value);
}}
</Consumer>
);
}
}
export default CountryList;
Trying to pass context value in CountryList but it's showing undefined, can't figure out why. Thanks in Advance
You need to wrap your CountryList component with Provider i.e you need to import Provider.
import React, { Component } from 'react';
import { Provider,Consumer } from '../../Context';
class CountryList extends Component {
render() {
return (
<Provider>
<Consumer>
{value => {
console.log('val:' + value);
}}
</Consumer>
</Provider>
);
}
}
export default CountryList;
Stackblitz example here : https://stackblitz.com/edit/react-143zwt
(I just added for testing. It will give you idea. I do not add this code there.)
I am using getInitialProps() in _App.js to grab some api data and I want to pass that data down as props to my other components via React Context. I want to initialize the Context Provider with state via the constructor.
First I initialize context via createContext().
config/Context.js:
import { createContext } from 'react';
const Context = createContext();
export default Context;
Then I create Context.Provider in its own component using constructor to initialize state.
provider/ContextProvider.js:
import React, { Component } from 'react';
import Context from '../config/Context';
class ContextProvider extends Component {
constructor(props) {
super(props);
this.state = {
filters: {
active: true,
headerActive: false
}
};
}
render() {
return (
<Context.Provider>
{this.props.children}
</Context.Provider>
);
}
}
export default ContextProvider;
In _app.js I make an API call within getInitialProps() and pass that data into the Context Provider.
pages/_app.js
import App, { Container } from 'next/app';
import ContextProvider from '../provider/ContextProvider';
import fetch from 'isomorphic-unfetch';
export default class MyApp extends App {
static async getInitialProps() {
const res = await fetch('https://node-hnapi.herokuapp.com/news');
let data = await res.json();
console.log(data)
return { articles: data }
}
render () {
const { Component, pageProps } = this.props;
return (
<Container>
<ContextProvider value={{ articles: this.props.articles}}>
<Component {...pageProps} />
</ContextProvider>
</Container>
);
}
}
At this point I assume that I would have access to context via Context.Consumer or a hook like useContext() but context is undefined in the following component:
components/ArticleList.js:
import React from 'react';
import Context from '../config/Context';
const ArticleList = () => {
const generateArticles = () => {
const context = React.useContext(Context);
console.log(context, 'context') // Context is undefined here
// return context.articles.map(article => <p>{article.title}</p>)
// Error: Cannot read property 'articles' because context is undefined
}
return (
<div>
<h3>Article List</h3>
{generateArticles()}
</div>
);
};
export default ArticleList;
Why is context undefined in components/ArticleList.js? I tried passing context into the component via Context.Consumer and I got the same result.
Here is repo replicating the issue: https://github.com/joelhoelting/next-context-api-test
In ContextProvider.js you forget to pass value to Context.Provider
import React, { Component } from 'react';
import Context from '../config/Context';
class ContextProvider extends Component {
constructor(props) {
super(props);
this.state = {
filters: {
active: true,
headerActive: false
}
};
}
render() {
const { value } = this.props
return (
<Context.Provider value={ value }>
{this.props.children}
</Context.Provider>
);
}
}
export default ContextProvider;
test.js
export default class TestScreen extends React.Component {
static contextType= AppProvider;
componentDidMount() {
console.log('test',this.context);
}
render() {
return (
<AppConsumer>
{ (context) => (
<p>{context.favoriteAnimal}</p>
)}
</AppConsumer>
)
}
}
store.js
const initialState = {
favoriteAnimal: "cow",
};
export const AppContext = React.createContext();
export const AppConsumer = AppContext.Consumer;
export class AppProvider extends React.Component {
constructor(props) {
super(props);
this.state = initialState;
}
render() {
return (
<AppContext.Provider value={{
favoriteAnimal: this.state.favoriteAnimal,
}}>
{this.props.children}
</AppContext.Provider>
);
}
}
dependencies: {
"react": "^16.8.4",
"react-dom": "^16.8.4",
"react-scripts": "2.1.8"
},
this.context is empty {},
in test.js. cant find a way out , any help will be appreciated. thank you
Problem is that you are assigning the ContextType to AppProvider which is your component instead of the context returned by React.createContext. Once you make this change, you don't even need to use AppConsumer inside of render method
export default class TestScreen extends React.Component {
static contextType= AppContext;
componentDidMount() {
console.log('test',this.context);
}
render() {
return (
<p>{this.context.favoriteAnimal}</p>
)
}
}
How to access the state variable testState from the different class UserAuthentication?
I have tried this without success:
import React from 'react';
import UserAuthenticationUI from './UserAuthentication/UserAuthenticationUI';
class App extends React.Component {
constructor(props) {
super(props);
this.userAuthenticationUI = React.createRef();
this.state={
testState: 'test message'
}
}
render() {
return(
<div>
<UserAuthenticationUI ref={this.userAuthenticationUI} />
<div>
)
}
}
export default App;
How to access this.state.teststate from class UserAuthenticationUI?
import React from "react";
import App from '../App';
class UserAuthenticationUI extends React.Component {
constructor(props) {
super(props);
this.app = React.createRef();
}
render() {
return(
<div>
<App ref={this.app} />
{console.log(this.state.testState)}
</div>
)
}
}
export default UserAuthenticationUI;
You need to pass it via props.
import React from "react";
import UserAuthenticationUI from "./UserAuthentication/UserAuthenticationUI";
class App extends React.Component {
constructor(props) {
super(props);
this.userAuthenticationUI = React.createRef();
this.setParentState = this.setParentState.bind(this);
this.state = {
testState: "test message"
};
}
setParentState(newStateValue){ // this is called from the child component
this.setState({
testState: newStateValue
})
};
render() {
return (
<div>
<UserAuthenticationUI
stateVariable={this.state.testState}
ref={this.userAuthenticationUI}
setParentState={this.setParentState}
/>
</div>
);
}
}
export default App;
UserAuthenticationUI:
import React from "react";
import App from "../App";
class UserAuthenticationUI extends React.Component {
constructor(props) {
super(props);
this.app = React.createRef();
this.onClick = this.onClick.bind(this);
}
onClick(){
const newStateValue = 'new parent state value';
if(typeof this.props.setParentState !== 'undefined'){
this.props.setParentState(newStateValue);
}
}
render() {
const stateProps = this.props.stateVariable;
return (
<div>
<App ref={this.app} />
<div onClick={this.onClick} />
{console.log(stateProps)}
</div>
);
}
}
export default UserAuthenticationUI;
You should think differently.
Try to read the variable via GET methods and set via SET methods.
Do not try to call the variable immediately
Hope this helps.
you can pass it through Props:
import React from 'react';
import UserAuthenticationUI from
'./UserAuthentication/UserAuthenticationUI';
class App extends React.Component {
constructor(props) {
super(props);
this.userAuthenticationUI = React.createRef();
this.state={
testState: 'test message'
}
}
render(){
return(
<div>
<UserAuthenticationUI testState={this.state.testState} />
<div>
)}
}
export default App;
UserAuthenticationUI:
import React from "react";
import App from '../App';
class UserAuthenticationUI extends React.Component
{
constructor(props){
super(props);
}
render(){
return(
<div>
<App/>
{console.log(this.props.testState)}
</div>
)}
}
export default UserAuthenticationUI;
You can access it via props:
<div>
<UserAuthenticationUI testState={this.state.testState} ref={this.userAuthenticationUI} />
<div>
and in UserAuthenticationUI class access it:
<div>
<App ref={this.app} />
{console.log(this.props.testState)}
</div>
Is there a way to access the props from react router in my App component? I am trying to access the this.props.location property from the BrowserRouter in App.js so that I can pass it into HeaderContainer.
index.js
function renderApp() {
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('react-app')
);
}
renderApp();
App.js
export default class App extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div id="app">
<HeaderContainer />
<Main />
<Footer />
</div>
);
}
}
You need to use withRouter HOC.
import React from 'react'
import PropTypes from 'prop-types'
import { withRouter } from 'react-router'
// A simple component that shows the pathname of the current location
class ShowTheLocation extends React.Component {
static propTypes = {
match: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
history: PropTypes.object.isRequired
}
render() {
const { match, location, history } = this.props
return (
<div>You are now at {location.pathname}</div>
)
}
}
export default withRouter(ShowTheLocation)
Reference:https://reacttraining.com/react-router/web/api/withRouter