I'm trying to figure out how to change language using React-Intl. This is my first React App and it has been made with create-react-app, I'm not using Redux nor Flux.
In my index.js I have the following code:
import React from 'react';
import ReactDOM from 'react-dom';
import TodoApp from './components/TodoApp';
import registerServiceWorker from './registerServiceWorker';
import './index.css';
// Bootstrap CSS libraries
import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap/dist/css/bootstrap-theme.css';
import { IntlProvider, addLocaleData } from 'react-intl';
import intlEN from 'react-intl/locale-data/en';
import intlES from 'react-intl/locale-data/es';
import intlMessagesES from './i18n/locales/es.json';
import intlMessagesEN from './i18n/locales/en.json';
addLocaleData([...intlEN, ...intlES]);
/* Define your translations */
let i18nConfig = {
locale: 'es',
messages: intlMessagesES
};
let changeLanguage = (lang) => {
i18nConfig = { locale: lang, messages: intlMessagesEN };
return i18nConfig;
}
ReactDOM.render(
<IntlProvider locale={ i18nConfig.locale } key={ i18nConfig.locale } messages={ i18nConfig.messages }>
<TodoApp onChangeLanguage={changeLanguage} />
</IntlProvider>,
document.getElementById('root'));
registerServiceWorker();
TodoApp is sending a string on 'lang' parameter by props (i.e.: 'es' or 'en'), when I change i18nConfig nothing seems to change with IntlProvider. My thought was that change my i18nConfig variable then all my app would change language as well.
I have FormattedMessages in TodoApp and my two JSON messages are filled like this:
// i18n/locales/en.json
{
"footer.add.placeholder": "Enter a name ...",
"footer.add.priority0.text": "No priority",
"footer.add.priority1.text": "Priority 1",
...
}
Do you know what am I missing on my code ?? Maybe I have not understand something right about React-Intl. Any advice will be helpful, thank you.
It works if you remove all from root:
ReactDOM.render(<TodoApp />, document.getElementById('root'));
But now we change TodoApp component like this:
1) We add 'locale' as component state and import React-Intl:
import { IntlProvider, addLocaleData } from 'react-intl';
import intlEN from 'react-intl/locale-data/en';
import intlES from 'react-intl/locale-data/es';
import intlMessagesES from './../i18n/locales/es.json';
import intlMessagesEN from './../i18n/locales/en.json';
addLocaleData([...intlEN, ...intlES]);
/* Define your default translations */
let i18nConfig = {
locale: 'en',
messages: intlMessagesEN
};
2) Change our changeLanguage function (this time called 'onChangeLanguage'), this function receives 'lang' from a subComponent language selector:
onChangeLanguage(lang) {
switch (lang) {
case 'ES': i18nConfig.messages = intlMessagesES; break;
case 'EN': i18nConfig.messages = intlMessagesEN; break;
default: i18nConfig.messages = intlMessagesEN; break;
}
this.setState({ locale: lang });
i18nConfig.locale = lang;
}
And finally render:
render() {
return (
<IntlProvider key={ i18nConfig.locale } locale={ i18nConfig.locale } messages={ i18nConfig.messages }>
<div>
<Header onChangeLanguage={this.onChangeLanguage} />
// Other components ...
</div>
</IntlProvider>
);
}
If someone doesn't understand at all, ask in comments! Thanks to #TomásEhrich
With a new React Context API it is quite easy to do. Create a wrapper:
import React from "react";
import Types from "prop-types";
import { IntlProvider, addLocaleData } from "react-intl";
import en from "react-intl/locale-data/en";
import de from "react-intl/locale-data/de";
import deTranslation from "../../lang/de";
import enTranslation from "../../lang/en";
addLocaleData([...en, ...de]);
const Context = React.createContext();
class IntlProviderWrapper extends React.Component {
constructor(...args) {
super(...args);
this.switchToEnglish = () =>
this.setState({ locale: "en", messages: enTranslation });
this.switchToDeutsch = () =>
this.setState({ locale: "de", messages: deTranslation });
// pass everything in state to avoid creating object inside render method (like explained in the documentation)
this.state = {
locale: "en",
messages: enTranslation,
switchToEnglish: this.switchToEnglish,
switchToDeutsch: this.switchToDeutsch
};
}
render() {
const { children } = this.props;
const { locale, messages } = this.state;
return (
<Context.Provider value={this.state}>
<IntlProvider
key={locale}
locale={locale}
messages={messages}
defaultLocale="en"
>
{children}
</IntlProvider>
</Context.Provider>
);
}
}
export { IntlProviderWrapper, Context as IntlContext };
And then use that Provider and Consumer:
import { Provider } from "react-redux";
import { IntlProviderWrapper } from "./IntlContext";
class App extends Component {
render() {
return (
<Provider store={store}>
<IntlProviderWrapper>
...
</IntlProviderWrapper>
</Provider>
);
}
}
somewhere in the app:
import React from "react";
import { Text, Button } from "native-base";
import { IntlContext } from "../IntlContext";
const LanguageSwitch = () => (
<IntlContext.Consumer>
{({ switchToEnglish, switchToDeutsch }) => (
<React.Fragment>
<button onClick={switchToEnglish}>
English
</button>
<button onClick={switchToDeutsch}>
Deutsch
</button>
</React.Fragment>
)}
</IntlContext.Consumer>
);
// with hooks
const LanguageSwitch2 = () => {
const { switchToEnglish, switchToDeutsch } = React.useContext(IntlContext);
return (
<>
<button onClick={switchToEnglish}>English</button>
<button onClick={switchToDeutsch}>Deutsch</button>
</>
);
};
export default LanguageSwitch;
Example on CodeSandbox
Here is the relevant repository with a more general solution.
Note: at the moment react-intl is still using an old context API but in the future solution like this might work out-of-the-box.
you can use redux manage your locale and localeMessage. just add a key in IntlProvider.
import React, { Component } from 'react';
import { IntlProvider } from 'react-intl';
class Inter extends Component {
render() {
let { locale, localeMessage, children } = this.props;
return (
<IntlProvider key={locale} locale={locale} messages={localeMessage}>
{children}
</IntlProvider>
)
}
};
export default Inter;
Related
I'm new to React and I'm trying to implement this example: https://react-selectable-fast.now.sh/
I couldn't make it work, because I can't solve this error: TypeError: Cannot read property 'getClientRects' of null.
This is my code:
index.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<App items={[{player: "Dirk Nowitzki", year: 1999}, {player: "Magic Johnson", year: 1980}, {player: "Michael Jordan", year: 1990}]}/>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint.
reportWebVitals();
App.jsx
import React, { Component } from 'react'
import { SelectableGroup } from 'react-selectable-fast'
import { createSelectable, SelectAll, DeselectAll } from 'react-selectable-fast'
import SomeComponent from './SomeComponent'
const SelectableComponent = createSelectable(SomeComponent)
class App extends Component {
handleSelecting() {
console.log("selecting");
}
handleSelectionClear() {
console.log("selection clear");
}
handleSelectionFinish() {
console.log("selection finish");
}
render() {
return (
<SelectableGroup
className="main"
clickClassName="tick"
enableDeselect
/*tolerance={this.state.tolerance}
globalMouse={this.state.isGlobal}*/
allowClickWithoutSelected={false}
duringSelection={this.handleSelecting}
onSelectionClear={this.handleSelectionClear}
onSelectionFinish={this.handleSelectionFinish}
ignoreList={['.not-selectable', '.item:nth-child(10)', '.item:nth-child(27)']}
>
<List items={this.props.items} />
</SelectableGroup>
)
}
}
class List extends Component {
render() {
this.props.items.map((item, i) => {
console.log(item.player, item.year, i);
})
return (
<div>
<SelectAll className="selectable-button">
<button>Select all</button>
</SelectAll>
<DeselectAll className="selectable-button">
<button>Clear selection</button>
</DeselectAll>
{this.props.items.map((item, i) => (
<SelectableComponent
key={i}
player={item.player}
year={item.year}
/>
))}
</div>
)
}
}
export default App;
SomeComponent.jsx
import React from 'react'
import { createSelectable } from 'react-selectable-fast'
const SomeComponent = ({ selectableRef, isSelected, isSelecting }) => (
<div ref={selectableRef} style={{
border: "1px solid blue",
width: "300px",
height: "300px",
float: "left",
}}
className="tick">...</div>
)
export default createSelectable(SomeComponent)
I also tried to delete node_modules and package-lock.json, then made npm install, but didn't work at all. I do not know if the error is from my code, because it has no reference to my jsx/js files. I noticed that I have 3 errors (for every objects in data array). Any help would be appreciated.
Screenshots of error:
Thanks in advance and have a great day!
I solved it. The problem was in SomeComponent.jsx.
Solution:
Delete
export default createSelectable(SomeComponent)
And change
const SomeComponent = ({ selectableRef, isSelected, isSelecting }) => (
Into
export const SomeComponent = ({ selectableRef, isSelected, isSelecting }) => (
I have the following problem: Using the code below I get the error:
this.props.posts is undefined
As I am following the tutorial https://codeburst.io/redux-a-crud-example-abb834d763c9 an I typed everything correct I am totally confused already at the beginning of my React career. Could you please help me?
import React, { Component } from 'react';
import { connect } from 'react-redux';
import Post from './Post';
class AllPost extends Component {
render() {
return (
<div>
<h1>All Posts</h1>
{this.props.posts.map((post) => <Post key={post.id} post={post} />)}
</div>
);
}
}
const mapStateToProps = (state) => {
return {
posts: state,
}
}
export default connect(mapStateToProps)(AllPost);
Thanks a lot for your efforts!
The following is the postReducer:
const postReducer = (state = [], action) => {
switch(action.type) {
case 'ADD_POST':
return state.concat([action.data]);
default:
return state;
}
}
export default postReducer;
And here the index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import postReducer from './reducers/postReducer';
const store = createStore(postReducer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>, document.getElementById('root'));
You need to declare an initial state. So your this.props.posts won't be undefined.
const initialState = {
posts: []
}
const postReducer = (state = initialState, action) => {
switch(action.type) {
case 'ADD_POST':
return { ...state, posts: [...state.posts, action.data]}
default:
return state;
}
}
export default postReducer;
The second error is located inside your mapStateToProps method. You need to access to posts redux state key. posts: state.posts like I did below
import React, { Component } from 'react';
import { connect } from 'react-redux';
import Post from './Post';
class AllPost extends Component {
render() {
return (
<div>
<h1>All Posts</h1>
{this.props.posts.map((post) => <Post key={post.id} post={post} />)}
</div>
);
}
}
const mapStateToProps = (state) => {
return {
posts: state.posts, // you need to access to posts key
}
}
export default connect(mapStateToProps)(AllPost);
This is a really long post, but I really need some help :/
I will be eternally grateful if someone would be able to help.
I have managed to get Auth0 working for an application i am working on with just react. It is an Overwatch SR tracker, and is essentially just a spreadsheet so I wasn't too concerned with protecting backend routes when I make them. There isn't any private information there.
My application state/props network became too complicated to manage, and through the process of implementing redux I simply cannot get it to work. I've been at it for three days, and I'm running out of ideas. Do I need Thunk with my current Auth setup to do this? I would imagine it is async since it needs to go get something that isnt there.
Granted I am a junior Dev, and dont have much experience with authentication. Can someone take a look at my working react application and guide me in the direction of what i may need to do to set it up with redux? I do have an understanding of redux flow, so if the proper method to do this was explained to me i feel i might get it.
here is some code:
my Auth.js file :
/*eslint no-restricted-globals: 0 */
import auth0 from "auth0-js";
import jwtDecode from 'jwt-decode';
const LOGIN_SUCCESS_PAGE = '/menu';
const LOGIN_FAILURE_PAGE = '/';
export default class Auth {
auth0 = new auth0.WebAuth({
domain: "redacted.auth0.com",
clientID: "redacted",
redirectUri: "http://localhost:3000/callback",
audience: "https://redacted.auth0.com/userinfo",
responseType: "token id_token",
scope: "openid profile"
});
constructor() {
this.login = this.login.bind(this);
}
login() {
this.auth0.authorize();
}
handleAuthentication() {
this.auth0.parseHash((err, authResults) => {
if (authResults && authResuslts.accessToken && authResults.idToken) {
let expiresAt = JSON.stringify((authResults.expiresIn) * 1000 + new Date().getTime());
localStorage.setItem("access_token", authResults.accessToken);
localStorage.setItem("id_token", authResults.idToken);
localStorage.setItem("expires_at", expiresAt);
location.hash = "";
location.pathname = LOGIN_SUCCESS_PAGE;
} else if (err) {
location.pathname = LOGIN_FAILURE_PAGE;
console.log(err);
}
});
}
isAuthenticated() {
let expiresAt = JSON.parse(localStorage.getItem('expires_at'));
return new Date().getTime() < expiresAt;
}
logout() {
localStorage.removeItem("access_token");
localStorage.removeItem("id_token");
localStorage.removeItem('expires_at');
location.pathname = LOGIN_FAILURE_PAGE;
}
getProfile() {
if (localStorage.getItem("id_token")) {
console.log(jwtDecode(localStorage.getItem("id_token")))
console.log(localStorage.getItem("id_token"));
return jwtDecode(localStorage.getItem("id_token"));
} else {
return {
name: 'Anon',
nickname: 'Anon',
picture: 'placeholder',
uid: null,
}
}
}
}
my index.js file:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import Auth from './Auth';
import { BrowserRouter } from 'react-router-dom';
const auth = new Auth();
let state = {};
window.setState = (changes) => {
state = Object.assign({}, state, changes)
ReactDOM.render(
<BrowserRouter>
<App {...state} />
</BrowserRouter>,
document.getElementById('root'));
}
/* eslint no-restricted-globals: 0*/
let getUserProfile = auth.getProfile();
let initialState = {
owSrTrackInfo: {
infoSaved: false,
accounts: [],
},
user: getUserProfile,
location: location.pathname.replace(/^\/?|\/$/g, ""),
auth,
}
window.setState(initialState);
registerServiceWorker();
my App.js file:
import React, { Component } from "react";
import "./App.css";
import Main from "./Components/Main/Main";
import Menu from "./Pages/Menu/Menu";
import NotFound from "./Components/NotFound/NotFound";
import Callback from './Components/Callback/Callback';
import Header from './Components/Header/Header';
class App extends Component {
render() {
let mainComponent = "";
switch (this.props.location) {
case "":
mainComponent = <Main {...this.props} />;
break;
case "callback":
mainComponent = <Callback />
break;
case "menu":
mainComponent = this.props.auth.isAuthenticated() ? < Menu {...this.props} /> : <NotFound />;
break;
default:
mainComponent = <NotFound />;
}
return (
<div className="app">
<Header {...this.props} />
{mainComponent}
</div>
);
}
}
export default App;
my Callback.js component:
import React, {Component} from 'react';
import Auth from '../../Auth'
export default class Callback extends Component {
componentDidMount() {
const auth = new Auth();
auth.handleAuthentication();
}
render() {
return(
<p className="loading">Loading.....</p>
)
}
}
My current MAIN.js component:
import React, { Component } from "react";
export default class Main extends Component {
render() {
console.log(this.props.auth.getProfile())
return (
<div className="container">
<div className='container--logged-out'>
<h1 className="heading u-margin-bottom-small">welcome to redacteds' overwatch sr tracker</h1>
<p>Hello there {this.props.user.nickname}! Sign in single click or email via Auth0 so we can save your results, and make the app usable by more than one person. I intend for more than one person to use this, so just to launch it and so the app knows your spreadsheet from someone elses I'll tie each user to their own UID. Feel free to come back, log in, and get your spreadsheet for the season back anytime.</p>
</div>
Go to the app menu!
<button onClick={() =>this.props.auth.getProfile()}>asdgkljsdngk</button>
</div>
);
}
}
my current HEADER.js component:
import React, { Component } from 'react';
export default class Header extends Component {
render() {
return (
<header className="header">
<h1 className='header__text'>SR TRACKER</h1>
{this.props.auth.isAuthenticated() ?
<button className='btn btn--logout' onClick={() => this.props.auth.logout()}>Logout</button>
:
<button className='btn btn--login' onClick={() => this.props.auth.login()}>Login or Sign Up</button>}
</header>
)
}
}
I simply want to map this authentication to a redux store instead to be consitent with the rest of my app (when redux is implemented) I have blown it away and started over multiple times, but a rough idea of what my redux flow might look like is like this template i use and have successfully implemented several times:
redux store:
import { createStore, compose, applyMiddleware } from 'redux';
import { createLogger } from 'redux-logger';
import thunk from 'redux-thunk';
import rootReducer from './reducers/rootReducer';
export default function configureStore(initialState) {
const middleware = [
createLogger({
collapsed: false,
duration: true,
diff: true,
}),
thunk,
];
const store = createStore(
rootReducer,
initialState,
compose(
applyMiddleware(...middleware),
window.devToolsExtension ? window.devToolsExtension() : format => format, // add support for Redux dev tools),
),
);
return store;
}
actionTypes.js in actions folder:
const actions = {
GET_FRIENDS: 'GET_FRIENDS',
REMOVE_FRIEND: 'REMOVE_FRIEND',
GET_MOVIES: 'GET_MOVIES',
GET_MOVIES_SUCCESS: 'GET_MOVIES_SUCCESS',
GET_MOVIES_FAILURE: 'GET_MOVIES_FAILURE',
DEVIN_FUN: 'DEVIN_FUN',
};
export default actions;
Sample actions page:
import axios from 'axios';
import actionTypes from './actionTypes';
export const getMoviesSuccess = data => {
return {
type: actionTypes.GET_MOVIES_SUCCESS,
data,
};
};
export const getMoviesFailure = () => {
return {
type: actionTypes.GET_MOVIES_FAILURE,
};
};
export const devinIsHavingFun = () => {
return {
type: actionTypes.DEVIN_FUN,
};
};
export const retrieveMovies = () => {
return function(dispatch) {
const API_KEY = 'trilogy';
dispatch(devinIsHavingFun());
axios
.get(`http://www.omdbapi.com?apikey=${API_KEY}&s=frozen`)
.then(data => {
dispatch(getMoviesSuccess(data.data.Search));
})
.catch(error => {
console.log(error);
dispatch(getMoviesFailure());
});
};
};
in the reducers folder wed have some files like initialState.js and root reducer that look like this respectively:
initialState.js:
export default {
friends: [],
movies: [],
};
rootReducer.js:
import { combineReducers } from 'redux';
import friends from './friendReducer';
import movies from './movieReducer';
const rootReducer = combineReducers({
friends,
movies,
});
export default rootReducer;
and a sample reducer:
import actionTypes from '../actions/actionTypes';
import initialState from './initialState';
export default function movieReducer(state = initialState.movies, action) {
switch (action.type) {
case actionTypes.GET_MOVIES_SUCCESS: {
return action.data;
}
default: {
return state;
}
}
}
I just dont know what to do. Do i need to use thunk? am I overthinking this? I'm pulling my hair out.
I also do connect my components in this fashion when redux is implemented :
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as friendActionCreators from './actions/friendActions';
import * as movieActionCreators from './actions/movieActions';
....................
function mapStateToProps(state) {
return {
myFriends: state.friends,
movies: state.movies,
};
}
function mapDispatchToProps(dispatch) {
return {
friendActions: bindActionCreators(friendActionCreators, dispatch),
movieActions: bindActionCreators(movieActionCreators, dispatch),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
Please let me know if anyone can point me in the right direction. thank you so much in advance.
We are currently struggling using Apollo Client to manage local state in a react application. We were able to build up a very simple example where we just display a div depending on the result of a mutation. The effect of the mutation should only be to display an alert message and return nothing.
We have come up with the following very simple example code:
File index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { ApolloClient } from 'apollo-client';
import { ApolloProvider } from 'react-apollo';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { withClientState } from 'apollo-link-state';
import App from './App';
const resolvers = {
Mutation: {
setData: (_, {myBool}) => {
alert(myBool);
return null;
}
}
};
const client = new ApolloClient({
cache: new InMemoryCache(),
link: withClientState({ resolvers })
});
ReactDOM.render(
<ApolloProvider client={client}>
<App />
</ApolloProvider>,
document.getElementById('root')
);
File App.js:
import React, { Component, Fragment } from 'react';
import gql from 'graphql-tag';
import { Mutation } from 'react-apollo';
class App extends Component {
setData = () => {
alert('setData is called');
const SET_DATA = gql`
mutation SetData($myBool: Boolean!) {
setData(myBool: $myBool) #client
}
`;
return (
<Mutation mutation={SET_DATA} variables={{ myBool: true }}>
{(_, { loading, error }) => (
<div>
{loading && <p>...loading...</p>}
{error && <p>ERROR ! Try reloading.</p>}
</div>
)}
</Mutation>
);
};
render() {
return (
<Fragment>
<h1>App</h1>
{this.setData()}
</Fragment>
);
}
}
export default App;
Could someone please tell us why the alert method we call in the setData() resolver (from file index.js) isn't called upon page loading?
I have been doing some experiment on React 16.3.1 ContextAPI. and I encountered into something that I couldn't fathom. I was hoping I could use your help.
Note: The problem have been solved but, its not the solution I am looking for.
Let start with first experiment on multiple components within same file Index.js.
import React, { Component, createContext } from 'react';
const { Provider, Consumer } = createContext();
class AppProvider extends Component {
state = {
name: 'Superman',
age: 100
};
render() {
const increaseAge = () => {
this.setState({ age: this.state.age + 1 });
};
const decreaseAge = () => {
this.setState({ age: this.state.age - 1 });
};
return (
<Provider
value={{
state: this.state,
increaseAge,
decreaseAge
}}
>
{this.props.children}
</Provider>
);
}
}
class Person extends Component {
render() {
return (
<div className="person">
<Consumer>
{context => (
<div>
<p>I'm {context.state.name}</p>
<p>I'm {context.state.age}</p>
<button onClick={context.increaseAge}>
<span>+</span>
</button>
<button onClick={context.decreaseAge}>
<span>-</span>
</button>
</div>
)}
</Consumer>
</div>
);
}
}
class App extends Component {
render() {
return (
<AppProvider>
<div className="App">
<p>Imma Apps</p>
<Person />
</div>
</AppProvider>
);
}
}
export default App;
As result, this render out perfect without any error. I am able to see name (Superman) and age (100). I am able to increase and decrease age by 1.
As you can see, I have imported {createContext} from react then created {Provider, Consumer}. Wrapped <Provider> with state value and <Consumer>.
Next Experiment, was exact copy each component from index.js and paste them separately into their own files.
AppProvider.js
import React, { Component, createContext } from 'react';
const { Provider, Consumer } = createContext();
class AppProvider extends Component {
state = {
name: 'Superman',
age: 100
};
render() {
const increaseAge = () => {
this.setState({ age: this.state.age + 1 });
};
const decreaseAge = () => {
this.setState({ age: this.state.age - 1 });
};
return (
<Provider
value={{
state: this.state,
increaseAge,
decreaseAge
}}
>
{this.props.children}
</Provider>
);
}
}
export default AppProvider;
Person.js
import React, { Component, createContext } from 'react';
const { Provider, Consumer } = createContext();
class Person extends Component {
render() {
return (
<div className="person">
<Consumer>
{context => (
<div>
<p>I'm {context.state.name}</p>
<p>I'm {context.state.age}</p>
<button onClick={context.increaseAge}>
<span>+</span>
</button>
<button onClick={context.decreaseAge}>
<span>-</span>
</button>
</div>
)}
</Consumer>
</div>
);
}
}
export default Person;
App.js
import React, { Component, createContext } from 'react';
const { Provider, Consumer } = createContext();
class App extends Component {
render() {
return (
<AppProvider>
<div className="App">
<p>Imma Apps</p>
<Person />
</div>
</AppProvider>
);
}
}
export default App;
As result, I am getting error - TypeError: Cannot read property 'state' of undefined.
I am unable to grasp what the exactly error was.. All I did was copy and paste each into files without changing any syntax.
Although, Alternative method was to create a new file and add syntax following...
Context.js
import { createContext } from 'react';
const Context = createContext();
export default Context;
Then go into each files (AppProvider.js. Person.js and App.js) and replace...
import React, { Component, createContext } from 'react';
const { Provider, Consumer } = createContext();'
...into...
import Context from './Context.js';. Also replace... <Provider> into <Context.Provider> and <Consumer> into <Context.Consumer>.
And this killed the error. However, this is not the solution I am looking for. I wanted to use <Provider> tag instead of <Context.Provider>.
Question is, Why am I getting this error?
Why am I unable to use this method...
import React, { Component, createContext } from 'react';
const { Provider, Consumer } = createContext();'
for each components in separate files so I could use <Provider> tag ?
Are there any way around to get the solution I'm looking for?
Your help is appreciated and Thanks in advance.
Your are getting TypeError: Cannot read property 'state' of undefined.
Beacuse every time you call const { Provider, Consumer } = createContext(); it creates a new object, this object need to be exported in order for consumers to consume this specific object.
So in person.js
when you try doing {context.state.age} it really does not have state on this object, you just created a new Context which is empty or rather with React internal methods and properties.
So in order to consume the same object just export it, like you did in Context.js and instead of doing:
import { createContext } from 'react';
const Context = createContext();
export default Context;
replace to:
import { createContext } from 'react';
const { Provider, Consumer } = createContext();
export { Consumer, Provider };
Then when you want to use it in other files ( meaning import it ) just call:
import { Consumer, Provider } from './Context.js';