I have a parent functional component named Dashboard and a child class component named DashboardTable. I'm making a graphql call in the parent class and want to pass the result into the child like this <DashboardTable data={opportunityData}/>.
problem: I can get see the data in the parent but its not showing in the child
Here is my code. Please let me know what I'm doing wrong
Dashboard
import React, { useEffect, useState } from "react";
import "bootstrap/js/src/collapse.js";
import DashboardTable from "../DashboardTable";
import { API } from "#aws-amplify/api";
import config from "../../aws-exports";
import * as queries from "../../graphql/queries";
export default function Dashboard() {
API.configure(config);
async function asyncCall() {
const gqlreturn = await API.graphql({
query: queries.listMockOppsTables,
});
//console.log(gqlreturn.data.listMockOppsTables); // result: { "data": { "listTodos": { "items": [/* ..... */] } } }
return gqlreturn;
}
const [opportunityTable, changeOpportunityTable] = useState(asyncCall());
console.log(opportunityTable); // this works! returns a promise
return (
<div>
<section className="py-5 mt-5">
<div className="container py-5">
<h2 className="fw-bold text-center">
Your upcoming shadowing events
<br />
<br />
</h2>
<DashboardTable data={opportunityTable}></DashboardTable>
</div>
</section>
</div>
);
}
DashboardTable
import React from "react";
import "bootstrap/js/src/collapse.js";
import Navigation from "../Navigation";
import { Link } from "react-router-dom";
import { API } from "#aws-amplify/api";
import config from "../../aws-exports";
import * as queries from "../../graphql/queries";
export class DashboardTable extends React.Component {
constructor() {
super();
this.state = {
opportunityData: this.props,
};
}
render() {
console.log(this.opportunityData); // this doesnt work :( no data
return (
<div>
<div
className="row row-cols-1 row-cols-md-2 mx-auto"
style={{ maxWidth: 900 }}
>
{this.opportunityData.map((opportunity) => (
<div className="col mb-4">
<div>
<a href="#">
<img
className="rounded img-fluid shadow w-100 fit-cover"
src="assets/img/products/awsLogo.jpg"
style={{
height: 250,
}}
/>
</a>
<div className="py-4">
<span
className="badge mb-2"
style={{ margin: 2, backgroundColor: "#ff9900" }}
>
{opportunity.interview_type}
</span>
<span
className="badge bg mb-2"
style={{ margin: 2, backgroundColor: "#ff9900" }}
>
{opportunity.level}
</span>
<span
className="badge bg mb-2"
style={{ margin: 2, backgroundColor: "#ff9900" }}
>
{opportunity.ShadowReverse}
</span>
</div>
</div>
</div>
))}
</div>
</div>
);
}
}
export default DashboardTable;
Few pointers
Call api on mount in parent's useEffect
In child directly use the passed property in child
function Dashboard() {
API.configure(config);
async function asyncCall() {
const gqlreturn = await API.graphql({
query: queries.listMockOppsTables,
});
//console.log(gqlreturn.data.listMockOppsTables); // result: { "data": { "listTodos": { "items": [/* ..... */] } } }
return gqlreturn;
}
// initialize with empty array
const [opportunityTable, changeOpportunityTable] = useState([]);
console.log(opportunityTable); // this works! returns a promise
// call api to fetch data on mount
useEffect(( => {
const fetchData = async () => {
const response = await asyncCall();
changeOpportunityTable(response)
}
fetchData()
}, [])
return (
<div>
<section className="py-5 mt-5">
<div className="container py-5">
<h2 className="fw-bold text-center">
Your upcoming shadowing events
<br />
<br />
</h2>
<DashboardTable data={opportunityTable}></DashboardTable>
</div>
</section>
</div>
);
}
class DashboardTable extends React.Component {
constructor() {
super();
//this.state = {
// opportunityData: this.props,
//};
}
render() {
console.log(this.props.data); // this doesnt work :( no data
return (
<div>
<div
className="row row-cols-1 row-cols-md-2 mx-auto"
style={{ maxWidth: 900 }}
>
//map thru data prop {this.props.data?.map((opportunity) => (
<div className="col mb-4">
<div>
<a href="#">
<img
className="rounded img-fluid shadow w-100 fit-cover"
src="assets/img/products/awsLogo.jpg"
style={{
height: 250,
}}
/>
</a>
<div className="py-4">
<span
className="badge mb-2"
style={{ margin: 2, backgroundColor: "#ff9900" }}
>
{opportunity.interview_type}
</span>
<span
className="badge bg mb-2"
style={{ margin: 2, backgroundColor: "#ff9900" }}
>
{opportunity.level}
</span>
<span
className="badge bg mb-2"
style={{ margin: 2, backgroundColor: "#ff9900" }}
>
{opportunity.ShadowReverse}
</span>
</div>
</div>
</div>
))}
</div>
</div>
);
}
}
Hope it helps
There are some bugs in the child like this.state.opportunityData = this.props, that end part should likely be this.props.opportunityData, however to get you going with the async call in the parent component give this a try
const [opportunityTable, changeOpportunityTable] = useState([]);
async function asyncCall() {
const gqlreturn = await API.graphql({
query: queries.listMockOppsTables,
});
changeOpportunityTable(gqlreturn);
}
useEffect(() => asyncCall(), []);
Related
I am having a single fruit with a list of infestations that I'm mapping on my react component. I want to open an ActionSheet with the details of an individual infestation when it is clicked. I have tried this way but its not working. Anyone, please help.
import React, { useState, useEffect, useRef } from "react";
import { Link, useNavigate, useParams } from "react-router-dom";
import Menubar from "../../components/menubar/Menubar";
import Tabs from "../../components/fruittabs/FruitTabs";
import WidgetSkeleton from "../../components/skeleton/WidgetSkeleton"
import Skeleton from "react-loading-skeleton";
import toast, { Toaster } from 'react-hot-toast';
import axios from 'axios';
import InfestationWidget from "../../components/widgets/InfestationWidget"
import ActionSheet from "actionsheet-react";
import { LazyLoadImage } from "react-lazy-load-image-component";
function FruitDetails() {
let navigate = useNavigate();
const [fruit, setFruit] = useState({});
const { fruitId } = useParams();
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
let isMounted = true;
axios.get(`/api/fruit/${fruitId}`).then(res => {
if (isMounted) {
if (res.data.status === 200) {
setFruit(res.data.fruit);
setIsLoading(false);
}
else if (res.data.status === 404) {
toast.error(res.data.message, "error");
}
}
});
return () => {
isMounted = false
};
}, []);
const ref = useRef(fruit.infestation && fruit.infestation.infestationid);
const handleOpen = () => {
ref.current.open();
console.log(`Fruit Infestation id: ${fruit.infestation.infestationid}`);
};
const handleClose = () => {
ref.current.close();
}
return (
<div>
<Menubar />
<div className="appHeader bg-primary text-light">
<div className="left">
<a onClick={() => navigate(-1)} className="headerButton goBack">
<i className="fi fi-rr-angle-left"></i>{" "}
</a>
</div>
<div className="pageTitle">{fruit.name}</div>
<div className="right"></div>
</div>
<Toaster />
<div id="appCapsule">
<div className="section mt-3 mb-3">
{isLoading ?
<Skeleton height={150} /> :
<LazyLoadImage
effect="blur"
width={'100%'}
src={`${process.env.REACT_APP_API_URL}/storage/fruits/${fruit.image}`}
alt="image"
className="imaged img-fluid fruit-detail-main"
/>}
</div>
<div className="section mt-3 mb-3">
<div>
<Tabs>
<div label="Details">
{isLoading && (
<Skeleton height={25} count="8" className="mb-05" />
)}
<div
dangerouslySetInnerHTML={{
__html: fruit.description,
}}
/>
</div>
<div label="Infestations">
<div className="mb-1">Here are some of the Popular Infestations for {fruit.name}</div>
<h3 className="mb-1">All Infestations</h3>
<div className="row">
{isLoading && <WidgetSkeleton cards={6} />}
{fruit.infestation && fruit.infestation.map((infestation) => (
<div className="col-6" infestation={infestation} key={infestation.infestationid}>
<div className="card mb-2">
<a onClick={handleOpen}>
<LazyLoadImage
src={`${process.env.REACT_APP_API_URL}/storage/infestations/${infestation.infestationimage}`}
className="card-img-top" alt="image" />
<div className="card-body card-bodysmall">
<p className="mb-0 text-sm-x">{infestation.infestationtype}</p>
<h4 className="mb-0">{infestation.infestationname}</h4>
</div>
</a>
</div>
</div>
))}
</div>
</div>
<div label="Advice">
<div
dangerouslySetInnerHTML={{
__html: fruit.advice,
}}
/>
</div>
</Tabs>
<ActionSheet
ref={ref}
sheetStyle={{
borderTopLeftRadius: 15,
borderTopRightRadius: 15,
height: '80%'
}}>
<div className="bar" />
//Single Fruit Infestation Details
</ActionSheet>
</div>
</div>
</div>
</div>
);
}
export default FruitDetails;
I'm working on a billing app. I have managed to fetch the Products from an API..... But now I'm trying to use useParams() to navigate to random pages that would display the items according to the ID by pressing a button...the navigation works fine but it wont display the data of that passed ID, it displays all the data in my API.
I would really appreciate some help or feedback, Thanks !
Item.js:
import React, { useEffect } from "react";
import { connect } from "react-redux";
import { getItems } from "../store/actions/itemsActions";
import { Link } from "react-router-dom";
import "./Items.css";
function Items({ getItems, items }) {
useEffect(() => {
getItems();
}, []);
function getRandomElFromArray(items) {
return Math.floor(Math.random() * items);
}
return (
<div>
<div className="container">
<div
className="image"
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: 200,
width: 100,
}}
>
<img src="http://i.stack.imgur.com/yZlqh.png" alt="" />
</div>
</div>
<div>
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<div className="item-preview">
{items &&
items.items &&
items.items.map((item) => (
<div key={item.id}>
<h4>
ID:<Link to={`/bills/${item.id}`}> {item.id}
<button className="button4">Analyse Receipt</button>
</Link>
</h4>
</div>
))}
</div>
</div>
</div>
</div>
);
}
const mapStateToProps = (state) => {
return {
items: state.items,
};
};
const mapDispatchToProps = (dispatch) => {
return {
getItems: () => dispatch(getItems()),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Items);
Billing.js:
import React, { useState } from "react";
import "./Bill.css";
import { Link, useParams, Switch, Route } from "react-router-dom";
import { connect } from "react-redux";
import { getItems } from "../store/actions/itemsActions";
function BillList({ items }) {
const [counter, setCounter] = useState(1);
const { id } = useParams();
function Display(props) {
return <label style={{ marginLeft: ".5rem" }}>{props.message}</label>;
}
return (
<div className="bills">
<div className="explore-container">
{items &&
items.items &&
items.items.filter((item) => item.id === id)
.map((item) => (
<div className="item-list" key={item.id}>
<h2>Title: {item.title}</h2>
<h4>price: {item.price}</h4>
</div>
))}
</div>
<div
className="main-title"
style={{
textAlign: "center",
justifyContent: "center",
alignItems: "center",
fontSize: 14,
}}
>
<h1>Bakery</h1>
<h1>Company Gbr</h1>
<h1>Oranienburger Straße 120</h1>
<h1>10119 Berlin</h1>
</div>
<div className="bills-container">
<div></div>
{/* pass in the details */}
<div className="item-list">
{items &&
items.items &&
items.items.map((item) => (
<React.Fragment key={item.id}>
<div className="bill-time">
<div className="bill">
<h4>
{" "}
<strong>Bill: </strong>
{item.billNumber}
</h4>
</div>
<div className="time">
<h4>
{" "}
<strong>Time: </strong>
{item.created_datetime}
</h4>
</div>
</div>
----------------------------------
----------------------------------
---------------------------------- --------------------
{/* Counter */}
<div className="price-total">
<div className="title">
<h3>
{" "}
<strong>Title: </strong>
{item.title}
</h3>
<div className="counter">
<strong>
<Display message={counter} />x
</strong>
</div>
</div>
<div className="increase">
<button onClick={() => setCounter(counter + 1)}>+</button>
</div>
<div className="decrease">
<button onClick={() => setCounter(counter - 1)}>-</button>
</div>
{/* Price and total */}
<div className="price">
<h4>
<strong>Price: {parseFloat(item.price)}€</strong>
</h4>
</div>
<div className="total">
<h4>Total: {parseFloat(item.price * counter)}€</h4>
</div>
</div>
</React.Fragment>
))}
</div>
{/* <div>
<h4>
Table: Counter
Terminal:
Ust-Id: DE11111111</h4>
</div> */}
</div>
<div className="button-path">
<Link to="/items">
<div className="button">
<button className="main-button">Analyse Receipt</button>
</div>
</Link>
</div>
<Switch>
<Route path="/bills/:id" />
</Switch>
</div>
);
}
const mapStateToProps = (state) => {
return {
items: state.items,
};
};
const mapDispatchToProps = (dispatch) => {
return {
getItems: () => dispatch(getItems()),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(BillList);
The ":" of path="/bills/:id" is only used to designate id as a route parameter, it isn't meant to be part of any URL. When you link to to={`/bills/:${items.id}`} you are adding ":" to the id string value.
Remove it from the link. You should also ensure that the Items component has items to map, where each specific item mapped renders the link/button to link to the appropriate bill list page.
<Link to={`/bills/${item.id}`}>
<button className="button4">Analyse Receipt</button>
</Link>
The Items route also doesn't specify any route params, so there will be be none in the `Items component.
<Route exact path="/" component={Items} />
I wanna dynamically render the images and then show the modal when the image is clicked and it should close when the modal background is clicked. Please help I'm new to React.
What should I do to make it work like is anything wrong in this. I'm stuck in this.
Whenever the images load from the api and I I click on them nothing happens.
import React from "react";
import axios from "axios";
import { Modal } from "./Modal";
class MediaGallery extends React.Component {
constructor() {
super();
this.state = {
data: "",
show: false,
loading: true
};
}
showModal = () => {
this.setState({ show: true });
};
hideModal = () => {
this.setState({ show: false });
};
componentDidMount() {
const url =
"https://amyapi.com";
axios
.get(url)
.then(response => {
this.setState({
data: response.data,
loading: false
});
})
.catch(error => {
console.log(error);
});
}
render() {
let content;
if (this.state.loading) {
content = (
<div>
<div className="modal is-active">
<div className="modal-background has-background-primary" />
<div className="modal-content has-text-centered">
<p classname="image is-48x48">
<img
src="https://raw.githubusercontent.com/sharadcodes/css_snippets/master/Infinity-1.4s-200px.gif?token=AIXQ22JWJBKUHGP45ANQZ4K5SW46A"
alt=""
/>
</p>
</div>
</div>
</div>
);
} else {
content = this.state.data.map((response, index) => {
return (
<div
key={index}
className="column is-one-quarter-desktop is-half-tablet"
style={{ cursor: "zoom-in" }}
onClick={this.showModal}
>
<Modal show={this.state.show} handleClose={this.hideModal}>
<img src={response.acf.image} alt={response.acf.title} />
</Modal>
<div className="card cardimages">
<div className="card-image" id="small-image-zoomable">
<figure className="image is-3by2">
<img src={response.acf.image} alt={response.acf.title} />
</figure>
<div
className="card-content is-overlay is-clipped"
data={response.acf.title}
>
<span className="tag is-primary">{response.acf.title}</span>
</div>
</div>
</div>
</div>
);
});
}
return (
<div>
<section className="hero is-medium is-bold has-background-black has-text-centered">
<div className="hero-body">
<div className="container">
<h1 className="title is-1" style={{ color: "#FFD581" }}>
Captured Moments
</h1>
</div>
</div>
</section>
<div className="section" style={{ marginTop: "-1.2rem" }}>
<div className="container">
<div className="columns is-multiline" id="media-gallery">
{content}
</div>
</div>
</div>
</div>
);
}
}
export default MediaGallery;
And modal code is
import React from "react";
export const Modal = ({ handleClose, show, children }) => {
const showHideClassName = show ? "is-active" : "";
return (
<div>
<div className={{ showHideClassName } + " modal"} id="modal">
<div className="modal-background" onClick={handleClose} />
<div className="modal-content" style={{ width: "70vw!important" }}>
<p className="image ">{children}</p>
</div>
<button
className="modal-close is-large"
aria-label="close"
onClick={handleClose}
/>
</div>
</div>
);
};
is there a correct manner to render in React using conditionals that I haven't figured out? I've spent some time with this and can't get why it only renders the 'Standard' .
Each one of the Standard, Filled, Premium components are simple rendering some HTML...
Here's what I've coded.
import React, { Component } from "react";
import { PropTypes } from "prop-types";
import { connect } from "react-redux";
import Standard from "./Standard";
import Filled from "./Filled";
import Premium from "./Premium";
class Plans extends Component {
constructor(props) {
super(props);
this.state = {
selectedplan: ""
};
this.onClick = this.onClick.bind(this);
}
onClick = e => this.setState({ selectedplan: e.target.name });
componentDidMount() {
if (this.props.auth.isAuthenticated) {
this.props.history.push("/dashboard");
}
}
render() {
var plan = this.state.selectedplan;
let content;
if (plan === "standard") {
content = <Standard />;
} else if (plan === "filled") {
content = "Testing... worked.?";
} else if (plan === "premium") {
content = <Premium />;
} else {
content = (
<div className="lead text-center">Select a plan to view more</div>
);
}
return (
<div>
<div className="row">
<div
className="col-sm-4 card card-info text-center justify-content-center"
style={{ margin: "auto" }}
>
<h3 onClick={this.onClick} name="standard">
Standard
</h3>
<ul>
<li />
</ul>
</div>
<div
className="col-sm-4 card text-center justify-content-center"
style={{ margin: "auto" }}
>
<h3 name="filled" onClick={this.onClick}>
Feature-Filled
</h3>
<ul>
<li />
</ul>
</div>
<div
className="col-sm-4 card card-info text-center justify-content-center"
style={{ margin: "auto" }}
>
<h3 name="premium" onClick={this.onClick}>
Super Premium
</h3>
<ul>
<li />
</ul>
</div>
</div>
<hr />
<div className="container text-center justify-content-center">
{content}
</div>
</div>
);
}
}
Plans.propTypes = {
auth: PropTypes.object.isRequired,
onClick: PropTypes.func.isRequired
};
const mapStateToProps = state => ({
auth: state.auth
});
export default connect(mapStateToProps)(Plans);
Thanks in advance!!
Maybe this will point you in the right direction.
class Plans extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedplan: ""
};
}
render() {
let { selectedplan } = this.state,
content;
if (selectedplan === "standard") {
content = <div>Standard</div>;
} else if (selectedplan === "filled") {
content = <div>Filled</div>;
} else if (selectedplan === "premium") {
content = <div>Premium</div>;
} else {
content = (
<div className="lead text-center">Select an option to view more</div>
);
}
return (
<div>
<div className="row">
<div
className="col-sm-4 card card-info text-center justify-content-center"
style={{ margin: "auto" }}
>
<h3
onClick={() => this.setState({ selectedplan: "standard" })}
name="standard"
>
Standard
</h3>
<ul>
<li />
</ul>
</div>
<div
className="col-sm-4 card text-center justify-content-center"
style={{ margin: "auto" }}
>
<h3
name="filled"
onClick={() => this.setState({ selectedplan: "filled" })}
>
Feature-Filled
</h3>
<ul>
<li />
</ul>
</div>
<div
className="col-sm-4 card card-info text-center justify-content-center"
style={{ margin: "auto" }}
>
<h3
name="premium"
onClick={() => this.setState({ selectedplan: "premium" })}
>
Super Premium
</h3>
<ul>
<li />
</ul>
</div>
</div>
<hr />
<div className="container text-center justify-content-center">
{content}
</div>
</div>
);
}
}
ReactDOM.render(<Plans />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<body>
<div id='root'></div>
</body>
I'm studying Reactjs and I'm building a tasks project (CRUD) but I'm stuck at the point of editing, the editing part is in another component and I'm not able to send the index of the task that will be edit, I read the documentation but I'm not capable to make it, please if someone can see my code and tell what I'm doing wrong.
the app (main)code
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
// data
import { todos2 } from './todos.json';
// subcomponents
import TodoForm from './components/TodoForm';
import TodoFormEdit from './components/TodoFormEdit';
class App extends Component {
constructor() {
super();
this.state = {
todos2, mode:'view'
}
this.handleAddTodo = this.handleAddTodo.bind(this);
this.handleEdit2 = this.handleEdit2.bind(this);
}
removeTodo(index) {
this.setState({
todos2: this.state.todos2.filter((e, i) => {
return i !== index
})
});
}
handleAddTodo(todo) {
this.setState({
todos2: [...this.state.todos2, todo]
})
}
handleEdit2(i) {
this.setState({mode: 'edit'});
//const mode = mode === 'edit';
alert(i);
/* alert(this.state.todos2[i].title);
alert(this.state.todos2[i].priority);
alert(this.state.todos2[i].description);
alert(this.state.todos2[i].language);*/
}
render() {
const todosAll = this.state.todos2.map((todo, i) => {
return (
<div className="col-md-4" key={i}>
<div className="card mt-4">
<div className="card-title text-center">
<h3>{todo.title} - { i } </h3>
<span className="badge badge-pill badge-danger ml-2">
{todo.priority}
</span>
</div>
<div className="card-body">
<div>
{todo.description}
</div>
<div>
{todo.language}
</div>
</div>
<div className="card-footer">
<button
className="btn btn-danger"
onClick={this.removeTodo.bind(this, i)}>
Delete
</button>
<button
className="btn btn-warning ml-2"
onClick={this.handleEdit2.bind(this, i)}>
Edit
</button>
</div>
</div>
</div>
)
});
return (
<div className="App">
<nav className="navbar navbar-dark bg-dark">
<a className="navbar-brand" href="/">
Tasks
<span className="badge badge-pill badge-light ml-2">
{this.state.todos2.length}
</span>
</a>
</nav>
<div className="container">
<div className="row mt-4">
<div className="col-md-4 text-center">
<img src={logo} className="App-logo" alt="logo" />
{/* <TodoForm onAddTodo={this.handleAddTodo} ></TodoForm> */ }
{this.state.mode === 'view' ? (
<TodoForm onAddTodo={this.handleAddTodo} />
) : (
<TodoFormEdit index={this.state.i}/>
)}
</div>
<div className="col-md-8">
<div className="row">
{todosAll}
</div>
</div>
</div>
</div>
</div>
)
}
}
export default App;
and the Edit component:
import React, { Component } from 'react';
// data
import { todos2 } from '../todos.json';
class TodoFormEdit extends Component {
constructor (i) {
super(i);
this.state = {
todos2
};
}
render() {
return (
<div>
{this.state.todos2[0].title}
</div>
)
}
}
export default TodoFormEdit;
You're passing this.state.i:
<TodoFormEdit index={this.state.i}/>
It's not clear where you set it–I see mode and todos2 state properties, I don't see i anywhere.