How to get state of _app.js in Next.js? - javascript

I have initiated a state in _app.js using Next.js.
I would like to use this state in the index.js file.
How can I access it?
This is my _app.js code:
import React from 'react';
import App, { Container } from 'next/app';
import Layout from '../components/Layout';
export default class MyApp extends App {
constructor(props) {
super(props);
this.state = {
currencyType: {
name: 'Ether',
price: 1,
},
ethPriceUsd: 1,
};
}
static async getInitialProps({ Component, router, ctx }) {
let pageProps = {};
let ethPriceUsd;
if (Component.getInitialProps) {
fetch(`https://api.coingecko.com/api/v3/coins/ethereum/`)
.then((result) => result.json())
.then((data) => {
ethPriceUsd = parseFloat(data.market_data.current_price.usd).toFixed(
2
);
});
pageProps = await Component.getInitialProps(ctx);
}
return { pageProps, ethPriceUsd };
}
componentDidMount() {
const ethPriceUsd = this.props.ethPriceUsd;
this.setState({ ethPriceUsd });
}
onCurrencyTypeChange(currencyTypeValue) {
let currencyType = {};
//Value comes from Header.js where Ether is 0 and USD is 1
if (currencyTypeValue) {
currencyType = {
name: 'USD',
price: this.state.ethPriceUsd,
};
} else {
currencyType = {
name: 'Ether',
price: 1,
};
}
alert('We pass argument from Child to Parent: ' + currencyType.price);
this.setState({ currencyType });
}
render() {
const { Component, pageProps } = this.props;
return (
<Container>
<Layout changeCurrencyType={this.onCurrencyTypeChange.bind(this)}>
<Component {...pageProps} />
</Layout>
</Container>
);
}
}
A lot of it is irrelevant (Like passing the data to the Layout etc...). All I want to do is use this state in my index.js.

let's say you have this code in _app.js.
import React from 'react'
import App, { Container } from 'next/app'
export default class MyApp extends App {
static async getInitialProps({ Component, router, ctx }) {
let pageProps = {}
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx)
}
return { pageProps }
}
state = {
name: "Morgan",
}
render () {
const { Component, pageProps } = this.props
return (
<Container>
<Component {...pageProps} {...this.state}/>
</Container>
)
}
}
Please notice the state and <Component {...pageProps} {...this.state}/>
Solution 1:
Now, let's see how can we use it in index.js or any other pages
import React from 'react';
export default class Index extends React.Component {
render() {
return (
<div>
<h2>My name is {this.props.name}</h2>
</div>
)
}
}
You can use them as props like this this.props.name
Solution 2:
Populate state in the index.js from props and then access it from state
import React from 'react';
export default class Index extends React.Component {
constructor(props) {
super(props)
this.state ={
name: this.props.name
}
}
render() {
return (
<div>
<h2>My name is {this.state.name}</h2>
</div>
)
}
}
You can use them as props like this this.state.name

Related

State is not passed down to child component

I have an issue in figuring in what conditions props are not passed down by the tree. I have a Fetcher class in which I populate with "layouts", then pass it to children props, but I cannot access it from child component.
EX:
import React, { Component } from 'react'
import axios from "axios";
export default class Fetcher extends Component {
constructor(props) {
super(props)
this.state = {
layouts: [],
}
componentDidMount() {
this.getLayouts();
}
getLayouts = () => {
axios
.get("/layout")
.then((res) => {
this.setState({
layouts: res.data,
});
})
.catch((err) => console.log(err));
};
render() {
return (
this.props.children(this.state.layouts)
)
}
}
This is my Parent component on which I pass some props children:
ex:
import React, { Fragment } from "react";
import Fetcher from "./Fetcher";
class App extends Component {
<Fetcher>
{(layouts) => {
return <Fragment>
<NewLayout
layoutsList={layouts} />
</Fragment>
}}
</Fetcher>
}
import React from "react";
class NewLayout extends React.Component {
constructor(props) {
super(props)
this.state = {
layouts: [],
}}
componentDidMount() {
this.setState(() => ({
layouts: this.props.layoutList
}))
}
render() {
{ console.log(this.state.layouts) }
{ console.log(this.props.layoutList) }
return (
....
The children prop is not a function, if you want to pass a property to it you should use React.Children API with React.cloneElement:
class Fetcher extends Component {
state = {
layouts: [/*some layout values*/],
};
render() {
const children = this.props.children;
const layouts = this.state.layouts;
return React.Children.map(children, (child) =>
React.cloneElement(child, { layouts })
);
}
}
Typo my friend, looks like you pass layoutsList prop to NewLayout, but internally use layoutList.

How to pass function from FUNCTIONAL to CLASS component and access it outside of render( without prop ), using context in react js?

How can I pass a function from FUNCTIONAL to CLASS component using context in react js?
My code:
CONTEXT:
authContext.js
import React from 'react'
const AuthContext = React.createContext()
export const AuthProvider = AuthContext.Provider
export const AuthConsumer = AuthContext.Consumer
export default AuthContext
FUNCTIONAL component:
App.js
...
import AuthPage from './pages/AuthPage';
import { AuthProvider } from './components/Context/authContext'
function App(props) {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const checkAuthenticated = async () => {
//console.time('fetch')
try {
const res = await fetch("http://localhost:4000/api/verify", {
method: "POST",
headers: { jwt_token: localStorage.token }
});
const parseRes = await res.json();
parseRes === true ? setIsAuthenticated(true) : setIsAuthenticated(false);
} catch (err) {
console.error(err.message);
}
//console.timeEnd('fetch')
};
const setAuth = boolean => {
setIsAuthenticated(boolean);
};
useEffect(() => {
checkAuthenticated();
}, [isAuthenticated, setAuth]);
return (
<Fragment>
<BrowserRouter basename={'/'}>
<GAListener>
<Switch>
<LayoutRoute
exact
path="/login"
layout={EmptyLayout}
component={props => (
<AuthProvider value={{ setAuth: setAuth }}>
<AuthPage {...props} authState={STATE_LOGIN} />
</AuthProvider>
)}
/>
<Redirect to="/" />
</Switch>
</GAListener>
</BrowserRouter>
</Fragment>
)
}
export default App;
CLASS component:
AuthForm.js
import AuthContext from '../components/Context/authContext'
class AuthForm extends React.Component {
constructor(props) {
super(props);
this.state = {
usernameInput: '',
emailInput: '',
passwordInput: '',
confirmPasswordInput: '',
remeberMe: false,
agreeTerms: false,
toDashboard: false
};
}
componentDidMount() {
if (localStorage.token) {
this.setState(() => (
{
toDashboard: true
}
))
}
}
componentDidUpdate() {
**// I WANT TO ACCESS THE 'setAuth' function here**
}
render() {
return (
<div>
//Some code
</div>
);
}
}
export default AuthForm;
Using setAuth function from AuthForm.js (class component), I want to change the value of isAuthenticated in App.js (functional component).
So, basically I want to access setAuth in componentDidUpdate().
Resolved the issue with the help from #gemhar
Changes to be made in AuthForm.js
...
import AuthContext from '../components/Context/authContext'
class AuthForm extends React.Component {
//Add this line
static contextType = AuthContext;
constructor(props) {
super(props);
this.state = {
usernameInput: '',
emailInput: '',
passwordInput: '',
confirmPasswordInput: '',
remeberMe: false,
agreeTerms: false,
toDashboard: false
};
}
componentDidMount() {
if (localStorage.token) {
this.setState(() => (
{
toDashboard: true
}
))
}
}
componentDidUpdate() {
//I can access setAuth here
this.context.setAuth(true)
//or by destructuring
let {setAuth} = this.context;
setAuth(true)
}
render() {
return (
<div>
//Some code
</div>
);
}
}
export default AuthForm;
The most common way to access Context from a class component is via the static contextType. If you need the value from Context outside of render, or in a lifecycle method, you'll use it this way.
import React from "react";
import AuthContext from "./context";
class AuthForm extends React.Component {
constructor(props) {
...
}
static contextType = AuthContext
componentDidUpdate() {
const {setAuth} = this.context
// Access the 'setAuth' function here
}
render() {
return <div>Some code</div>;
}
}
export default AuthForm;

Can i pass component state to HoC?

Is there any way to send data from the component's state to HoC?
My component
import React, { Component } from 'react';
import withHandleError from './withHandleError';
class SendScreen extends Component {
contructor() {
super();
this.state = {
error: true
}
}
render() {
return (
<div> Test </div>
)
}
};
export default withHandleError(SendScreen)
My HoC component:
import React, { Component } from 'react';
import { ErrorScreen } from '../../ErrorScreen';
import { View } from 'react-native';
export default Cmp => {
return class extends Component {
render() {
const { ...rest } = this.props;
console.log(this.state.error) //// Cannot read property 'error' of null
if (error) {
return <ErrorScreen />
}
return <Cmp { ...rest } />
}
}
}
Is there any way to do this?
Is the only option is to provide props that must come to the SendScreen component from outside??
A parent isn't aware of child's state. While it can get an instance of a child with a ref and access state, it can't watch on state updates, the necessity to do this indicates design problem.
This is the case for lifting up the state. A parent needs to be notified that there was an error:
export default Cmp => {
return class extends Component {
this.state = {
error: false
}
onError() = () => this.setState({ error: true });
render() {
if (error) {
return <ErrorScreen />
}
return <Cmp onError={this.onError} { ...this.props } />
}
}
}
export default withHandleError(data)(SendScreen)
In data you can send the value you want to pass to HOC, and can access as prop.
I know I answer late, but my answer can help other people
It is very easy to do.
WrappedComponent
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import HocComponent from './HocComponent';
const propTypes = {
passToHOC: PropTypes.func,
};
class WrappedComponent extends Component {
constructor(props) {
super(props);
this.state = {
error: true,
};
}
componentDidMount() {
const {passToHOC} = this.props;
const {error} = this.state;
passToHOC(error); // <--- pass the <<error>> to the HOC component
}
render() {
return <div> Test </div>;
}
}
WrappedComponent.propTypes = propTypes;
export default HocComponent(WrappedComponent);
HOC Component
import React, {Component} from 'react';
export default WrappedComponent => {
return class extends Component {
constructor() {
super();
this.state = {
error: false,
};
}
doAnything = error => {
console.log(error); //<-- <<error === true>> from child component
this.setState({error});
};
render() {
const {error} = this.state;
if (error) {
return <div> ***error*** passed successfully</div>;
}
return <WrappedComponent {...this.props} passToHOC={this.doAnything} />;
}
};
};
React docs: https://reactjs.org/docs/lifting-state-up.html
import React, { Component } from 'react';
import withHandleError from './withHandleError';
class SendScreen extends Component {
contructor() {
super();
this.state = {
error: true
}
}
render() {
return (
<div state={...this.state}> Test </div>
)
}
};
export default withHandleError(SendScreen)
You can pass the state as a prop in your component.

Render whole html file in react component

I am serving some content from my API.
I want display response from API in my react component.
Response is html with bundled all assets inline by webpack.
How can I do it?
I tried dangerouslySetInnerHTML but it crashes my javascript inside returned html.
My cmp :
import React, { Component } from 'react';
import axios from 'axios';
export default class Report extends Component {
constructor() {
super();
this.state = {
id: null,
report: null
};
}
getParam(param){
return new URLSearchParams(window.location.search).get(param);
}
componentWillMount() {
axios.post(`/url`,
{
'id': this.getParam('id'),
}
)
.then(res => {
this.setState({id: res.data});
setTimeout(() => {
axios.get(`https://rg.ovh/`+this.state.id)
.then(res => {
this.setState({report: res.data})
});
}, 1900);
});
}
render() {
return (
<div dangerouslySetInnerHTML={ {__html: this.state.report} } />
);
}
}
import axios from 'axios';
import React, { Component } from 'react';
import renderHTML from 'react-render-html';
class App extends Component {
constructor() {
super();
this.state = {
htmlString: ''
};
}
componentDidMount() {
axios.get('http://localhost:5000').then(response => {
this.setState({ htmlString: response.data })
}).catch(err => {
console.warn(err);
});
}
render() {
const { htmlString } = this.state;
return (
<div className="App">
{renderHTML(htmlString)}
</div>
);
}
}
export default App;

Cannot figure out why data won't load into React component

Here is my store:
import helper from './../../helpers/RestHelpers.js';
var posts = [];
class PostStore {
constructor() {
helper.get('/api/posts')
.then((data) => {
posts = data;
console.log(posts);
}
);
}
getPosts() {
return posts;
}
};
export default new PostStore();
When I console.log posts from within the helper function, I get the correct data. But when I console.log from the component, the array of posts is empty.
Here is my component:
import React from 'react';
import postStore from '../stores/PostStore';
class Home extends React.Component {
constructor() {
super();
this.state = {
posts: postStore.getPosts()
}
console.log(this.state.posts);
}
render() {
return (
<div className="welcome">
{this.state.posts.map(function(post, index) {
return (
<PostItem post={post} key={"post " + index} />
)
})
}
</div>
)
}
}
class PostItem extends React.Component {
render() {
return <div>{this.props.post.postName}</div>;
}
}
export default Home;
I wouldn't use your PostStore as-is. Instead just use your helper directly like so:
import React from 'react';
// import your helper!
class Home extends React.Component {
componentDidMount() {
helper.get('/api/posts').then((data) => {
this.setState({posts: data})
});
}
render() {
return (
<div className="welcome">
{this.state.posts.map((post, idx) => <PostItem post={post} key={"post " + idx} />)}
</div>
)
}
}

Categories

Resources