This question already has answers here:
How to pass data from child component to its parent in ReactJS?
(18 answers)
Closed 1 year ago.
I want to send variable data Store component to Related Component, I am getting Value const catId=this.state.data.category_id; now i am sending via props to Related Component but I dont know how to use props in Realted Component, i want to assign inside of didmonunt function for example
const url = "https://localhost:3030/api/v5/web/related";
const postBody = {
category_id: catId,
here my code:
Store.js
import React, { Component } from "react";
// import ReactDOM from "react-dom";
import { Helmet } from "react-helmet";
import { Grid, Image, Icon, Segment, Card } from "semantic-ui-react";
import TopMenuStrip from "../ComponentList/TopMenuStrip";
import LogoSection from "../ComponentList/LogoSection";
import { withRouter } from "react-router-dom";
import OfferList from "./OfferList";
import Related from "./Related";
import CopyRight from "../ComponentList/CopyRight";
import Footer from "../ComponentList/Footer";
import CustomerReview from "./CustomerReview";
class Store extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
isLoading: true,
};
}
async componentDidMount() {
console.log(this.props.match.params.id);
let url_id = this.props.match.params.id;
const url = "https://localhost:3030/api/v5/web/details";
const postBody = {
store_id: url_id,
offer_type: "",
};
const requestOptions = {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(postBody),
};
fetch(url, requestOptions)
.then((response) => response.json())
.then((json) => {
this.setState({ data: json });
//console.log(json);
// console.log(json);
})
.catch((error) => console.error(error))
.finally(() => {
this.setState({ isLoading: false });
});
}
render() {
var i;
// console.log(this.props)
if (!this.state.data.how_to) {
return null;
}
if (!this.state.data.store_terms) {
return null;
}
const catId=this.state.data.category_id;
const seokeyWord = this.state.data.seo_keywords;
const seoDescription = this.state.data.seo_description;
return (
<>
<Helmet>
<meta charSet="utf-8" />
<title>test</title>
<meta name="description" content={seokeyWord} />
<meta name="keywords" content={seoDescription} />
<meta name="google-site-verification" content="rtIRrUNRpgZ_lFtlfS8LJ0-8j_d569BXS9NOGa_nM6Y" />
</Helmet>
<TopMenuStrip />
<LogoSection />
<div>
<Grid className="storedetails">
<Grid.Column width={11}>
<div className="storeImage">
<div className="store-bg">
<h2>
<span>{this.state.data.store_name}</span>
<span className="store-right">
{
(i =
0 < this.state.data.rating ? (
<p>
<span className="rateNumber">
{this.state.data.rating}
</span>
<Icon id={i} className="star"></Icon>
</p>
) : (
<p className="no-reviews">No Reviews</p>
))
}
</span>
</h2>
<p className="">{this.state.data.summary} </p>
{/* <p><span className='rateNumber'>{this.state.data.rating}</span><Icon className='star'/><Icon className='star'/><Icon className='star'/><Icon className='star'/><Icon className='star'/><span className='totalRate'>39000</span></p> */}
<div
className="store-back"
Style={
"background: url(" + this.state.data.store_images + ")"
}
>
{/* <Image src= alt="" className='storeImage'/> */}
<Image
src={this.state.data.logo}
alt=""
className="storeImageLogo"
/>
</div>
</div>
<div className="related-section">
<OfferList />
</div>
</div>
</Grid.Column>
<Grid.Column className="four-1" width={5}>
<div className="storeAbout" centered>
<h3>About</h3>
<p
dangerouslySetInnerHTML={{
__html: this.state.data.description,
}}
></p>
</div>
<CustomerReview />
<Related CatID={catId}/>
</Grid.Column>
</Grid>
<Grid className="related-footer">
<Grid.Column width={16}>
</Grid.Column>
</Grid>
</div>
<Footer />
<CopyRight />
</>
);
}
}
export default withRouter(Store);
Related.js
import React, { Component } from 'react';
// import ReactDOM from "react-dom";
import { Grid, Icon, Segment, Card } from "semantic-ui-react";
import { Link } from "react-router-dom";
import { LazyLoadImage } from 'react-lazy-load-image-component';
class Related extends Component{
constructor(props) {
super(props);
this.state = {
data: [],
visible: 6,
isLoading: true,
dataLoaded: false,
rec:CatID,
};
this.loadMore = this.loadMore.bind(this);
}
loadMore() {
this.setState({
visible: this.state.visible + 2,
dataLoaded: this.state.visible >= this.state.data.length
});
}
async componentDidMount() {
// console.log(this.props.match.params.id);
const url = "https://localhost:3030/api/v5/web/related";
const postBody = {
category_id: CatID,
offer_type: "",
};
const requestOptions = {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(postBody),
};
fetch(url, requestOptions)
.then((response) => response.json())
.then((json) => {
this.setState({ data: json.stores });
// console.log(json);
// console.log(json);
})
.catch((error) => console.error(error))
.finally(() => {
this.setState({ isLoading: false });
});
}
render()
{
return (
<>
<div className="related-stores" centered>
<h3 className="realted-heading">Related Stores </h3>
<Grid className="">
{this.state.data.slice(0, this.state.visible).map((x, i) => {
return (
<Grid.Column columns={8} key={i}>
<Segment>
<Card>
<Link to={x.store_url}>
<div className="image">
<LazyLoadImage src={x.image} wrapped ui={false} className="img related"/>
</div>
</Link>
<LazyLoadImage src={x.logo} alt="" className="collection-logo" />
<Card.Content>
<Link to={x.store_url}>
{" "}
<Card.Header>{x.name}</Card.Header>
</Link>
<Card.Description>{x.store_summary}</Card.Description>
</Card.Content>
<Card.Content extra>
<p className="rewards">
<span>
<LazyLoadImage src="/images/rewards.png" alt="" className="img"/>
</span>
Cash rewards upto <span>AED {x.cashback}</span>
</p>
<p className="location">
<span>
<LazyLoadImage src="/images/location.png" alt="" className="img"/>
</span>
<span className="store-location" key="index">{x.store_branches}</span>
{/* {x.store_branches.map((locations, index) => (
<span className="store-location" key="index">
{index === 0 ? (
<span>{locations.store_location}</span>
) : index >= 1 ? (
<span>
, {locations.store_location}
</span>
) : null}
</span>
))} */}
</p>
</Card.Content>
</Card>
</Segment>
</Grid.Column>
);
})}
</Grid>
{
!this.state.dataLoaded && (
<Grid>
<Grid.Column width={16}>
<p className="related-load">
<span
onClick={this.loadMore}
className="btn btn-primary load-more"
Style="cursor:pointer;">
Loading Store
</span>
</p>
</Grid.Column>
</Grid>
)
}
</div>
</>
)
}
}
export default Related;
In the Store component, pass storeCategory as props to the Related component.
In the Related component, access categoryId from the props and set it as category_id in postBody.
class Related extends Component {
...
async componentDidMount() {
...
const postBody = {
category_id: this.props.categoryId,
...
}
...
}
class Store extends Component {
...
render() {
...
return(
...
<Related categoryId={storeCategory} />
...
);
}
}
Explanation:
Related is a child of Store (parent).
To pass data from a parent component to a child component, use props.
Set an attribute on , e.g. categoryId, and assign the data (storeCategory) to it:
<Related categoryId={storeCategory} />
Store will then receive categoryId among its props. In Store, you can thus access categoryId from the props:
this.props.categoryId
Further reading:
Components and props
Related
I developed small application with catch all route method url is http://localhost:3000/category/fashion/19see the bellow image
Now I am using getServerSideProps method working fine, and changed to getStaticProps method error displayed, bu want use getStaticPaths method, I got dynamic values using context.params.Id[0]=fashion and context.params.Id1=19, But can not call this value inside of getStaticPaths, What I am missing and can you please solve this issue please.
category/[...Id].js
import { useRouter } from 'next/router'
import Head from 'next/head'
import { Grid, Image,Segment, Card } from "semantic-ui-react"
import 'semantic-ui-css/semantic.min.css'
import Layout from '../../components/layout'
const Post = (props) => {
const router = useRouter()
const { Id } = router.query
console.log(props.category_list)
return(
<>
<Layout>
<Head>
<meta charSet="utf-8" />
<title>Test</title>
{/* <meta name="description" content={seo_description} /> */}
<meta name="keywords" content=""/>
<meta name="google-site-verification" content="rtIRrUNRpgZ_lFtlfS8LJ0-8j_d569BXS9NOGa_nM6Y" />
</Head>
<Grid className="store-list">
<Grid.Column width={16}>
<p>
<span>{props.category_title.heading_label}</span>
</p>
</Grid.Column>
</Grid>
<Grid columns={4} className="all-offers storeList">
{props.category_list.map((x) => {
return (
<Grid.Column>
<Segment>
<Card>
<a href ={x.store_url}>
{" "}
<Image
src={x.image}
alt=""
className="collection-img"
></Image>
</a>
<Card.Content>
<a href ={x.store_url}>
{" "}
<Card.Header>{x.name}</Card.Header>
</a>
<Card.Description>{x.store_summary}</Card.Description>
</Card.Content>
<Card.Content extra>
<p className="rewards">
<span>
<img src="/images/rewards.png" alt=""></img>
</span>
Cash rewards upto <span>AED {x.cashback}</span>
</p>
<p className="location">
<span>
<img src="/images/location.png" alt=""></img>
</span>
<span className="store-location" key="index">{x.store_branches}</span>
{/* {x.store_branches.map((locations, index) => (
<span className="store-location">
{index === 0 ? (
<span>{locations.store_location}</span>
) : index >= 1 ? (
<span>
, {locations.store_location}
</span>
) : null}
</span>
))} */}
</p>
</Card.Content>
</Card>
</Segment>
</Grid.Column>
);
})}
</Grid>
</Layout>
</>
)
}
export async function getStaticPaths() {
// How to call context value here
return { paths, fallback: 'blocking' }
}
export async function getStaticProps(context) {
const id = context.params.Id[1];
const postBody = {
category_id: id,
offer_type: "",
};
const offerList = await fetch('https://lenapp.ae/api/v5/web/list',{
method:'POST',
body: JSON.stringify(postBody),
headers: { "Content-Type": "application/json" },
})
const category = await offerList.json();
// const bookJson = JSON.stringify(book)
// const bookJson=offerData.stores;
const category_list=category.stores;
const category_title=category;
return {
props: {
category_list,
category_title
}
};
}
export default Post;
export async function getStaticPaths() {
//How to call context value here - explaining
const res = await fetch('your_api_path')
const posts = await res.json()
//params: {id: post.id} - this is your value will be fashion or 19, check the data/field you receiving
const paths = posts.map((post) => ({
params: { id: post.id },
}))
return { paths, fallback: 'blocking' }
}
For the nested dynamic routes: You can create /category/[style](folder)/[id](file). I suggest you make firstly with getServerSideProps all your pages and routing, and then do with getStaticProps.
So I'm trying to get some data from my api and then select that data and send it to the other api, but I can't figure it out how to select the data.
import React, { Component } from 'react'
import Dropdown from 'react-dropdown'
import 'react-dropdown/style.css'
class Testas extends Component {
constructor(props){
super(props);
this.state = {
}
}
componentDidMount() {
const headers = {
'Authorization': 'Bearer ',''
};
fetch(`https://spiceworks/api/printserver/printers`,{ headers }
)
.then(res => res.json())
.then(json => {
this.setState({
isLoaded: true,
items: json.printers,
})
});
}
render() {
const { items } = this.state
const type = ['test', 'python', 'web', 'all']
const amount = [1,2,3,4,5,6,7,8,9,10]
return (
<div className="content">
<form>
<div className="row">
<div className="col-sm">
<div className="card">
<div className="card-body">
<h3 className="card-title">Printer Test</h3>
<Dropdown className="drop" options={this.state.items} placeholder="Pasirinkti printerį" />
<Dropdown className="drop2" options={type} placeholder="BÅ«das" />
<Dropdown className="drop2" options={amount} placeholder="Kiekis" />
Test
</div>
</div>
</div>
</div>
</form>
</div>
)
}
}
export default Testas
the data I recieve from api looks like this
{
"printers": [
"ZEB-SOFA15",
"ZEB-120",
"GDX-SOFUZ4",]}
i tried with e value onchange code but then I always get error that data.map is not a function.
I'm trying to develop a website for fetching GitHub data, but I'm having problem in updating the component that shows data Formdata component. It doesn't seem to be updating form some reasons.
App:
export default class App extends Component {
constructor(props){
super(props);
this.state = {
uname:'',
udata:'',
};
this.handleInput = this.handleInput.bind(this);
this.getUser = this.getUser.bind(this);
}
getUser(){
fetch(`https://api.github.com/users/${this.state.uname}`)
.then(response => response.json())
.then(data => this.setState({udata:data}))
.catch(error => console.error(error));
}
handleInput(event){
this.setState({
uname:event.target.value
});
}
render() {
return (
<div>
<Header></Header>
<Form handleInput={this.handleInput} uname={this.state.uname} getUser={this.getUser}></Form>
<Formdata udata={this.state.udata}></Formdata>
</div>
)
}
}
Form:
export default function Form(props) {
const {getUser, handleInput, uname} = props;
return (
<div className="form">
<input className="textbar" placeholder="Search for username" value={uname} onChange={handleInput} name="uname"></input>
<button className="button" onClick={getUser} >Search</button>
</div>
)
}
Formdata:
export default class Formdata extends Component {
constructor(props){
super(props);
this.state = {
follower:'',
following:'',
public_repos:'',
visit_page:'',
avatar:''
}
this.updateUser = this.updateUser.bind(this);
};
componentDidMount(props){
this.updateUser();
}
updateUser(){
this.setState({follower:this.props.udata.followers});
this.setState({following:this.props.udata.following});
this.setState({public_repos:this.props.udata.public_repos});
this.setState({visit_page:this.props.udata.url});
this.setState({avatar:this.props.udata.avatar_url});
console.log(this.props.udata);
}
render() {
return (
<div>
<img className="imge" src= {this.state.avatar} alt=" "></img>
<div className="details">
<div className="compon">Followers: {this.state.followers}</div>
<div className="compon">Following: {this.state.following}</div>
<div className="compon">public repos" {this.state.public_repos}</div>
</div>
<div className="urls">Page:{this.state.visit_page}</div>
</div>
)
}
}
I can't figure out how to update component Formdata on clicking search button in Form component.
Full Working App: StackBlitz
import React, { Component, useEffect } from "react";
import "./style.css";
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
uname: "",
udata: ""
};
this.handleInput = this.handleInput.bind(this);
this.getUser = this.getUser.bind(this);
}
getUser() {
fetch(`https://api.github.com/users/${this.state.uname}`)
.then(response => response.json())
.then(data =>
this.setState({ udata: data }, () => {
console.log(this.state.udata);
})
)
.catch(error => console.error(error));
}
handleInput(event) {
this.setState(
{
uname: event.target.value
},
() => {
console.log(this.state.uname);
}
);
}
render() {
return (
<div>
<Form
handleInput={this.handleInput}
uname={this.state.uname}
getUser={this.getUser}
/>
<Formdata udata={this.state.udata} />
</div>
);
}
}
const Form = props => {
const { getUser, handleInput, uname } = props;
return (
<div className="form">
<input
className="textbar"
placeholder="Search for username"
value={uname}
onChange={handleInput}
name="uname"
/>
<button className="button" onClick={getUser}>
Search
</button>
</div>
);
};
const Formdata = ({ udata }) => {
useEffect(() => {
console.log(JSON.stringify(udata.login));
}, [udata]);
return (
<div style={styles.card}>
{udata.login ? (
<div style={styles.cardImg}>
<div>
<img
style={styles.img}
className="imge"
src={udata?.avatar_url}
alt=" "
/>
</div>
<div className="details">
<div className="compon">Followers: {udata?.followers}</div>
<div className="compon">Following: {udata?.following}</div>
<div className="compon">Public repos: {udata?.public_repos}</div>
<div className="urls">Page: {udata?.url}</div>
</div>
</div>
) : (
<div>
<p>No Data Available</p>
</div>
)}
</div>
);
};
const styles = {
card: {
display: "flex",
flex: 1,
backgroundColor: "rgba(21,21,21,0.2)",
padding: 10,
marginTop: 10,
borderRadius: 5
},
cardImg: {
display: "flex",
flex: 1,
flexDirection: "row",
flexWrap: "wrap",
overflow: "hidden",
textOverflow: "ellipsis",
color: "rgba(0,0,0,0.7)"
},
img: {
marginRight: 10,
width: 100,
height: 100,
borderRadius: 10,
overflow: "hidden"
}
};
Do not copy props into state, use the props directly in your JSX:
div>
<img className="imge" src= {this.props.udata.avatar} alt=" "></img>
<div className="details">
<div className="compon">Followers: {this.props.udata.followers}</div>
<div className="compon">Following: {this.props.udata.following}</div>
<div className="compon">public repos" {this.props.udata.public_repos}</div>
</div>
<div className="urls">Page:{this.props.udata.visit_page}</div>
</div>
If you copy props into state, you are creating redundant copy of props and it is difficult to keep props and state in sync. And it is a React anti-pattern.
Just make sure this.props.udata is not undefined, it is ok if it is empty object {}. If it is undefined, put a check / conditional rendering.
anti-pattern-unconditionally-copying-props-to-state
Formdata.updateUser() isn't being called at any point. You probably just need to call it in componentDidMount():
export default class Formdata extends Component {
...
componentDidMount(props){
this.updateUser();
}
updateUser(){
this.setState({follower:this.props.udata.followers});
this.setState({following:this.props.udata.following});
this.setState({public_repos:this.props.udata.public_repos});
this.setState({visit_page:this.props.udata.url});
this.setState({avatar:this.props.udata.avatar_url});
console.log(this.props.udata);
}
...
}
import React, { Component, useState } from 'react';
import algoliasearch from 'algoliasearch/lite';
import {
InstantSearch,
Hits,
SearchBox,
Highlight,
connectRefinementList,
} from 'react-instantsearch-dom';
import PropTypes from 'prop-types';
import './App.css';
const searchClient = algoliasearch(
'test',
'test'
);
class App extends Component {
constructor(props) {
super(props);
this.state = {
selectedCountries: []
}
}
render() {
const RefinementList = ({
items,
isFromSearch,
refine,
searchForItems,
createURL,
}) => {
return (
<ul style={{ listStyle: 'none' }}>
{
items &&
items.map(item => (
<li key={item.label}>
<input
type="checkbox"
checked={item.isRefined}
// href={createURL(item.value)}
style={{ fontWeight: item.isRefined ? 'bold' : '' }}
onChange={event => {
// event.preventDefault();
refine(item.value);
}}
/>
{isFromSearch ? (
<Highlight attribute="label" hit={item} />
) : (
item.label
)}{' '}
({item.count})
</li>
))}
</ul>
)
};
const CustomRefinementList = connectRefinementList(RefinementList);
return (
<div className="container">
<InstantSearch searchClient={searchClient} indexName="parterns">
<div className="search-panel">
<div className="search-panel__results">
<SearchBox
className="searchbox"
translations={{
placeholder: '',
}}
searchAsYouType={false}
/>
<Hits hitComponent={Hit} />
<br />
<br />
<button onClick={(e) => {
const that = this;
e.preventDefault();
that.setState({
selectedCountries: Array.from(new Set([...that.state.selectedCountries, 'India']))
})
}
}
>
Select India
</button>
<br />
<button onClick={(e) => {
const that = this;
e.preventDefault();
that.setState({
selectedCountries: Array.from(new Set([...that.state.selectedCountries, 'USA']))
})
}
}
>
Select Usa
</button>
<br />
<h3>Location</h3>
<div className="region">
<CustomRefinementList
operator="or"
limit={10}
defaultRefinement={[]}
attribute="region" />
</div> <br />
<CustomRefinementList
operator="or"
limit={this.state.selectedCountries.length}
defaultRefinement={this.state.selectedCountries}
attribute="country" />
<br />
<br />
</div>
</div>
</InstantSearch>
</div>
);
}
}
function Hit(props) {
return (
<article onClick={() => alert(props.hit.title)}>
<h1>
<Highlight attribute="title" hit={props.hit} />
</h1>
</article>
);
}
Hit.propTypes = {
hit: PropTypes.object.isRequired,
};
export default App;
The problem is all previously selected filters are getting cleared.
For example initially I click on filter ex: North America
So I will get filtered results for North America.
Now I want to have Country filter which will be visible when click on button ex Select USA
When I am clicking on Button for ex: Select USA then I am setting state because I want to render it dynamically but issue is previous state is getting cleared how can I preserve previous state for component.
I am trying to generate expansion panels based on fetching API, which I have done successfully. The problem that I am having is that when I try to generate the data on the expansion panels, it shows all sets of data, where I want it to show one set of data per expansion panel. I used the Expansion Panel Component from material-ui
class FetchData extends Component {
constructor(props) {
super(props);
this.state = {
isLoaded: false,
items: [],
}
}
componentDidMount() {
fetch(url , {
method: 'get',
mode: 'cors',
headers: {
'X-API-KEY': API_KEY,
'Access-Control-Allow-Origin': '*',
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then(res => res.json())
.then(json => {
this.setState({
isLoaded: true,
items: json,
})
})
};
render() {
const { classes } = this.props;
var{ isLoaded, items } = this.state;
if(!isLoaded) {
return <div>Loading...</div>
}
else{
return (
<div className="container">
<ul>
{items.map((item) => (
<li>
<ExpansionPanel />
</li>
))}
</ul>
</div>
);
}
}
}
export default FetchData;
Code for ExpansionPanel
function DetailedExpansionPanel(props) {
const { classes } = props;
return (
<div className={classes.root}>
<ExpansionPanel>
<ExpansionPanelSummary expandIcon={<img src={ExpandMoreIcon} alt="EMI"/>} >
<div className={classes.column}>
{this.item.props.device_id}
</div>
<div className={classes.column}>
</div>
</ExpansionPanelSummary>
<ExpansionPanelDetails className={classes.details}>
<div className={classes.column} />
<div className={classes.column}>
<Chip label="Barbados" className={classes.chip} onDelete={() => {}} />
</div>
<div className={classNames(classes.column, classes.helper)}>
<Typography variant="caption">
Select your destination of choice
<br />
<a href="#sub-labels-and-columns" className={classes.link}>
Learn more
</a>
</Typography>
</div>
</ExpansionPanelDetails>
<Divider />
<ExpansionPanelActions>
<Button size="small">Cancel</Button>
<Button size="small" color="primary">
Save
</Button>
</ExpansionPanelActions>
</ExpansionPanel>
</div>
);
}
DetailedExpansionPanel.propTypes = {
classes: PropTypes.object.isRequired,
};