State is not passed down to child component - javascript

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.

Related

My React function being passed down as props is not being invoked

I am trying to re-render the page based on a button click. I have the function updateCowList which calls setState() in my app component. The handleClick logic is in my newCow component which handles the button and the text input.
The console.logs() that I am seeing are 'fire', but I am not seeing the 'after' console.log(), nor am I seeing any of the logs within my updateCowList function in App.
How can I get my updateCowList function to run? I have tried calling it in all sorts of ways, destructuring props, etc.
Here is my App:
import React from 'react';
import CowList from './CowList.jsx';
import CowListEntry from './CowListEntry.jsx';
import axios from 'axios';
import SearchDB from './searchDB.js';
import NewCow from './NewCow.jsx';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
cows: []
}
// this.updateCowList = this.updateCowList.bind(this);
}
componentDidMount() {
SearchDB()
.then((res) => {
this.setState({cows: res.data})
}, (err) => {
console.log(err);
});
}
updateCowList(cow) {
console.log('update cow list is running')
oldCows = [...this.state.cows];
newCows = oldCows.push(cow);
console.log('new cows be4 set state', newCows);
this.setState({cows: newCows});
console.log('new cows after set state', newCows);
}
render() {
return (
<div>
<CowList cows={this.state.cows}/>
<NewCow props={this.updateCowList}/>
</div>
)
}
}
export default App;
here is my NewCow component:
import React from 'react';
import axios from 'axios';
class NewCow extends React.Component {
constructor(props) {
super(props);
this.state = {
entry: ''
};
this.handleChange = this.handleChange.bind(this);
this.handleClick = this.handleClick.bind(this);
}
handleClick () {
let split = this.state.entry.split(', ')
console.log(split)
axios.post('http://localhost:3000/api/cows', {
name: split[0],
description: split[1]
})
.then(res => { console.log('fire', res.data);
this.props.updateCowList(res.data);
console.log('after')
})
.catch(err => 'error submitting cow :( mooooo');
}
handleChange (event) {
this.setState({entry: event.target.value})
}
render () {
return (
<div className='newCowForm'>
<input className='form-control' type='text' onChange={this.handleChange} value={this.state.entry} placeholder={'name, description'} />
<button onClick={this.handleClick} className='newCowButton'>Create new cow</button>
</div>
)
}
}
export default NewCow;
<NewCow props={this.updateCowList}/>
should be :
<NewCow updateCowList={this.updateCowList}/>

passing data from the parent component state to the child component using React.createContext

I have a component that contains a state, and I will pass the state data into another component, I use a static contextType to throw the state data but the data does not reach the intended component, what do you think this is wrong? thank you
this is my parent component
export const MyContext = React.createContext();
export class MerchantByPromo extends Component {
constructor(props) {
super(props);
this.state = {
dataPromo: [],
loading: true
};
}
async componentDidMount() {
const merchant_id = this.props.match.params.id_merchant
await Api.post('language/promo-voucher-by-merchant', { MERCHANT_ID: merchant_id })
.then((response) => {
if (response.data.STATUS_CODE === '200') {
this.setState({
dataPromo: response.data.DATA,
loading: false
});
}
})
}
this is my child component
import React, { Component } from 'react'
import { MyContext } from './MerchantByPromo'
export class MerchantByPromoDetail extends Component {
constructor(props){
super(props)
this.state = {
detailPromo:[],
}
}
UNSAFE_componentWillMount(){
let value = this.context
console.log(value)
}
componentDidMount(){
}
render() {
return (
<MyContext.Consumer>
<p>tes</p>
</MyContext.Consumer>
)
}
}
I always get an error message like this "TypeError: render is not a function", what's the solution?
<MyContext.Consumer>
{() => <p>tes</p>}
</MyContext.Consumer>
change to this and Check

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.

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

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

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;

Categories

Resources