Redirect to another page after GET call in modal form in React - javascript

I am trying to redirect to another page after fetch GET call from Modal from in react using history.props and I redirected but I don't know what should write there to show my actual data. I editied somehting i added something in history.props and componentDidMount in Report Here is my code:
import React, { Component } from "react";
import Datee from "./Date";
import { withRouter } from "react-router";
export class CarReports extends Component {
constructor(props) {
super(props);
this.state = {
selectOptions: [],
movie: [],
mov: "",
query: "",
results: []
};
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
}
async handleSubmit(e) {
let authToken = localStorage.getItem("Token");
try {
const from = e.target.elements.from.value;
const to = e.target.elements.to.value;
const selections = [...e.target.elements.selectOptions.options].filter(
opt => opt.selected
);
const selectedValues = selections.map(opt => opt.value);
const selectedString = selectedValues.join(",");
e.preventDefault();
const res = await fetch(
`http://localhost:8000/api/1/deliveries/report/?date__lte=${to}&date__gte=${from}&user=${selectedString}`,
{
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: "Bearer " + JSON.parse(authToken)
}
}
);
const movie = await res.json();
console.log(movie);
this.setState({
movie
});
this.props.history.push({
pathname: "/carreport",
state: movie
});
} catch (e) {
console.log(e);
}
}
handleChange = e => {
let target = e.target;
let name = target.name;
//here
let value = Array.from(target.selectedOptions, option => option.value);
this.setState({
[name]: value
});
};
render() {
return (
<div id="car" class="modal">
<a
href="# "
rel="modal:close"
className="float-right text-white h4"
style={{
background: "#b71c1c",
borderRadius: "50%",
padding: "10px",
height: "32px",
lineHeight: "10px"
}}
>
×
</a>
<p className="mod" style={{ marginTop: "40px" }}>
CARS REPORT
</p>
<form style={{ marginTop: "20px" }} onSubmit={this.handleSubmit}>
<div>
<Datee />
</div>
<div className="form-group" style={{ marginTop: "20px" }}>
<label style={{ opacity: "0.6", fontSize: "10px" }}>
CHOOSE A CAR
</label>
<select
name="selectOptions"
style={{ width: "390px" }}
multiple={true}
onChange={this.handleChange}
value={this.state.selectOptions}
class="form-control"
>
<option value="1">Choose Car From List</option>
<option value="1">General Score</option>
<option value="2">Dynamic</option>
<option value="3">Speed</option>
<option value="4">Fuel Save</option>
</select>
</div>
<div style={{ marginTop: "50px" }}>
<center>
<button
type="submit"
value="Get Data"
className="btn btn-login text-white font-weight-bolder boxx "
style={{
height: "40px",
fontSize: "13px",
lineHeight: "30px",
width: "200px",
background: "rgba(183, 28, 28, 1)",
border: "none",
color: "white",
margin: "auto"
}}
>
RAPORT
</button>
</center>
</div>
</form>
</div>
);
}
}
export default withRouter(CarReports);
Here is my careport.js page where I want to display data. I don't know what to do here.
import React, { Component } from "react";
import ReactToExcel from "react-html-table-to-excel";
import CarReports from "../CarReports";
class Report extends Component {
componentDidMount() {
const movie = this.props.location.state.movie;
this.setState({
movie
});
console.log(movie)
}
render() {
return (
<div className="container" style={{ marginTop: "50px" }}>
<CarReports />
<div className="headerr" style={{ marginTop: "25px" }}>
<h6>CAR REPORT</h6>
<p className="p">From 12-17-2019 To 12-12-2019</p>
<div className="driver report">
<table className="table" id="table-to-xls">
<thead>
<tr>
<th>No</th>
<th>Full Name</th>
<th>Car Quantity</th>
<th>Mileage[Km]</th>
<th>Fuel Consumed[L]</th>
<th className="t">
Average Fuel<br></br> Consumed[L/100km]
</th>
<th className="t">Overspeed Distance[%]</th>
<th className="t">
Critical <br></br>Overspeed [qty.]
</th>
<th>Score: Overall</th>
</tr>
</thead>
<tfoot>
<tr className="thead">
<th></th>
<th>Summary</th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</tfoot>
</table>
<div style={{ marginTop: "40px" }}>
<center>
<a className="btn" href="#car" rel="modal:open" id="bttt">
NEW REPORT
</a>
<ReactToExcel
className="btn btn-success btn-lg bb"
table="table-to-xls"
filename="SoftbikeReport"
sheet="sheet 1"
buttonText="EXPORT CSV"
/>
</center>
</div>
</div>
</div>
</div>
);
}
}
export default Report;

You can pass state when redirecting using react-router's state API like so:
/** INSIDE CarReports.jsx */
export class CarReports extends Component {
...
async handleSubmit() {
...
const res = await fetch(...);
...
const movie = await res.json();
this.setState({ movie });
this.props.history.push({
pathname: "/carreport",
state: movie
});
}
...
}
You can then access the fetch results inside CarReport.jsx like so:
export class CarReport extends Component {
componentDidMount() {
const movie = this.props.location.state.movie;
}
...
}
here are some more resources:
How do i pass state through React_router?
https://tylermcginnis.com/react-router-pass-props-to-link/

Related

delete button does not read id if modal added in ReactJS

I have created a CRUD application and successfully it is performing all the operations.
But when I try to create a modal so that it shows up a warning either to delete the id or not on clicking delete. And If I try to delete a particular id from the modal I'm unable to delete the selected item, else it is deleted the latest id in the list.
What might be the problem that is making me not delete a particular id from the list only when creating a modal.
Help me how I can make it work.
This is the button to open the warning modal:
const [open, setOpen] = useState(false);
const toggle = () => setOpen(!open);
<button onClick={toggle}>
<MdIcons.MdDelete color='black' fontSize="1.3rem"/>delete</button>
This is the modal that opens after clicking delete:
<Modal isOpen={open} toggle={toggle}>
<ModalHeader toggle={toggle}>Warning</ModalHeader>
<ModalBody>Are you sure to delete this id from the list...</ModalBody>
<ModalFooter>
<Button onClick={() => onDelete(data.id)}>YES</Button>
<Button onClick={toggle}>Cancel</Button>
</ModalFooter>
</Modal>
In the above modal I have give the onclick event for button YES to delete the id selected, but the delete functionality is not working when I use it on a modal.
These are the button functionalities:
const getData = () => {
axios.get(`https://62c45bb0abea8c085a73b996.mockapi.io/Reactcrud`)
.then((getData) => {
setAPIData(getData.data);
})
}
const onDelete = (id) => {
axios.delete(`https://62c45bb0abea8c085a73b996.mockapi.io/Reactcrud/${id}`)
.then(() => {
getData();
})
}
Please help me how I can achieve the functionality of deleting the particular id after modal opens, and let me know if you need any more details regarding my code.
I am new to react, i don't know if my explanation will be correct, my theory is that the problem was this: You were rendering the modal for every record, and only the last modal remained.
I put the modal outside the loop, and i declared a useState to track the selected id to delete, it worked =D
Read.js :
import axios from "axios";
import React, { useEffect, useState } from "react";
import { Table, Button, List, Popup, Grid, Icon, Dropdown, Menu, Header } from "semantic-ui-react";
import { useNavigate, Link } from "react-router-dom";
import * as MdIcons from "react-icons/md";
import * as AiIcons from "react-icons/ai";
import * as FiIcons from "react-icons/fi";
import { Modal, ModalFooter, ModalHeader, ModalBody } from "reactstrap";
import SideMenu from "../SideMenu/SideMenu";
function Read() {
const [APIData, setAPIData] = useState([]);
const [idToDelete, setIdToDelete] = useState(0);
useEffect(() => {
axios.get(`https://62c45bb0abea8c085a73b996.mockapi.io/Reactcrud`).then((response) => {
console.log(response.data);
setAPIData(response.data);
});
}, []);
const setData = (data) => {
let {
id,
image,
companyName,
email,
companyNumber,
uniqueNumber,
lineofBusiness,
companyRevenue,
openingTime,
closingTime,
discount,
rating,
address1,
address2,
pincode,
area,
city,
state,
country,
} = data;
localStorage.setItem("ID", id);
localStorage.setItem("Image", image);
localStorage.setItem("Email", email);
localStorage.setItem("Company Name", companyName);
localStorage.setItem("Company Number", companyNumber);
localStorage.setItem("Unique Number", uniqueNumber);
localStorage.setItem("Line of Business", lineofBusiness);
localStorage.setItem("Company Revenue", companyRevenue);
localStorage.setItem("Opening Time", openingTime);
localStorage.setItem("Closing Time", closingTime);
localStorage.setItem("Discount", discount);
localStorage.setItem("Rating", rating);
localStorage.setItem("Address1", address1);
localStorage.setItem("Address2", address2);
localStorage.setItem("Pincode", pincode);
localStorage.setItem("Area", area);
localStorage.setItem("City", city);
localStorage.setItem("State", state);
localStorage.setItem("Country", country);
};
const getData = () => {
axios.get(`https://62c45bb0abea8c085a73b996.mockapi.io/Reactcrud`).then((getData) => {
setAPIData(getData.data);
});
};
const onDelete = () => {
axios
.delete(`https://62c45bb0abea8c085a73b996.mockapi.io/Reactcrud/${idToDelete}`)
.then(() => {
navigate("/company/list");
toggle();
})
.then(() => {
getData();
});
};
let navigate = useNavigate();
const addUser = () => {
navigate("/company/create");
};
const [open, setOpen] = useState(false);
const toggle = () => setOpen(!open);
const [search, setSearch] = useState("");
return (
<>
<div className="container-fluid">
<div className="row">
<div className="col-lg-12" style={{ marginLeft: "-11px" }}>
<SideMenu />
</div>
</div>
<div className="row">
<div className="col-lg-3"></div>
<div className="col-lg-6">
<Button primary style={{ width: "150px", height: "40px" }} onClick={addUser}>
Add Company
</Button>
<input
type="text"
value={search}
onChange={(e) => setSearch(e.target.value)}
placeholder="Search by any Category"
style={{
position: "absolute",
width: "260px",
height: "40px",
marginLeft: "285px",
border: "none",
fontSize: "15px",
padding: "8px",
borderRadius: "20px 20px 20px 20px",
}}
/>
<table style={{ width: "700px", height: "200px" }}>
<thead style={{ margin: "50px" }}>
<tr>
<th style={{ textAlign: "center" }}>List of Companies</th>
</tr>
</thead>
{APIData.filter((data) =>
Object.values(data).some((value) => value.toLowerCase().includes(search.toLowerCase()))
).map((data, id) => {
return (
<>
<tbody key={id}>
<li
style={{
minHeight: "140px",
borderRadius: "5px",
margin: "20px 0px",
listStyle: "none",
padding: "25px",
backgroundColor: "white",
boxShadow: "0 0 20px 0px rgba(0,0,0,0.2)",
}}
>
<tr>
<Link to="/company/view">
<button
style={{
background: "transparent",
border: "none",
color: "blue",
}}
onClick={() => setData(data)}
>
{data.companyName}
</button>
</Link>
</tr>
<tr>{data.companyNumber}</tr>
<tr>{data.uniqueNumber}</tr>
<tr>{data.lineofBusiness}</tr>
</li>
<div
style={{
position: "absolute",
marginLeft: "580px",
marginTop: "-120px",
}}
>
<Dropdown
icon={
<AiIcons.AiOutlineEllipsis
style={{
color: "black",
fontSize: "1.3rem",
marginTop: "15px",
marginLeft: "30px",
border: "1px solid black",
width: "30px",
height: "30px",
borderRadius: "50%",
}}
/>
}
pointing="top right"
>
<Dropdown.Menu>
<Dropdown.Item icon="edit" text="Edit">
<Link to="/company/edit">
<button
onClick={() => setData(data)}
style={{
background: "transparent",
border: "none",
}}
>
<FiIcons.FiEdit color="black" fontSize="1.3rem" /> Edit
</button>
</Link>
</Dropdown.Item>
<Dropdown.Item icon="delete" text="Delete">
<button
onClick={() => {
setIdToDelete(data.id);
toggle();
}}
style={{
background: "transparent",
border: "none",
}}
color="red"
>
<MdIcons.MdDelete color="black" fontSize="1.3rem" />
delete
</button>
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</div>
</tbody>
</>
);
})}
</table>
<Modal isOpen={open} toggle={toggle}>
<ModalHeader toggle={toggle}>Warning</ModalHeader>
<ModalBody>Are you sure to delete this id from the list...</ModalBody>
<ModalFooter>
<Button color="red" onClick={onDelete}>
Okay
</Button>
<Button color="primary" onClick={toggle}>
Cancel
</Button>
</ModalFooter>
</Modal>
</div>
</div>
</div>
</>
);
}
export default Read;

Displaying data from SQL Table into React.js Frontend based on what option is selected in <select> tag

I am trying to display data so for example if "brkalk" is selected in the tag it only displays "brkalk" table row and its content. I tried doing ? and : along with useState but it did not work because I have the .map function so I had problems with closing "}". Some tags and table names are in Bosnian so don't worry about that :)
import React, { useState, useEffect } from 'react'
import axios from 'axios'
import "./Modal.css";
export default function Modal() {
const [modal, setModal] = useState(false);
const [database, setDatabase] = useState();
const getData = async () => {
try {
await axios.get("http://localhost:3001/data").then((response) => {
setDatabase(response.data)
})
}
catch (e) {
console.log(e)
}
}
useEffect(() => {
getData()
}, [])
const toggleModal = () => {
setModal(!modal);
};
if (modal) {
document.body.classList.add('active-modal')
} else {
document.body.classList.remove('active-modal')
}
return (
<>
<button onClick={toggleModal} className="btn-modal">
Tabela gotovinskih racuna
</button>
{modal && (
<div className="modal">
<div onClick={toggleModal} className="overlay"></div>
<div className="modal-content">
<h2>Tabela gotovinskih racuna</h2>
<select name="filters" id="filters">
<option value="brkalk">brkalk</option>
<option value="sifpar">sifpar</option>
</select>
<table style={{
border: "2px solid black",
margin: "auto",
marginTop: "25px",
marginBottom: "5px",
width: "95%"
}}>
<thead>
<tr>
<th>brkalk</th>
<th>datum</th>
<th>uempl</th>
<th>siforg</th>
<th>ziral</th>
<th>kartica</th>
<th>obust</th>
<th>sifpar</th>
<th>zakljucan</th>
<th>povrat</th>
<th>brkalkfisk</th>
<th>brkalkpov</th>
<th>regbroj</th>
<th>vozac</th>
<th>sifkart</th>
<th>idslog</th>
<th>idfirma</th>
<th>racunar</th>
<th>iznosf</th>
</tr>
</thead>
{database?.map((i) =>
<tbody style={{
textAlign: "center",
}}>
<tr>
<td>{i.brkalk}</td>
<td>{i.datum}</td>
<td>{i.uempl}</td>
<td>{i.siforg}</td>
<td>{i.ziral}</td>
<td>{i.kartica}</td>
<td>{i.obust}</td>
<td>{i.sifpar}</td>
<td>{i.zakljucan}</td>
<td>{i.povrat}</td>
<td>{i.brkalkfisk}</td>
<td>{i.brkalkpov}</td>
<td>{i.regbroj}</td>
<td>{i.vozac}</td>
<td>{i.sifkart}</td>
<td>{i.idslog}</td>
<td>{i.idfirma}</td>
<td>{i.racunar}</td>
<td>{i.iznosf}</td>
</tr>
</tbody>
)}
</table>
<button className="close-modal" onClick={toggleModal}>
CLOSE
</button>
</div>
</div>
)}
</>
);
}

How to handle multiple Switch button React js?

I am trying to use multiple switch button in react js , I tried but i could not get positive result i want to do main button notification when click on notification all button should checked and also i can check or uncheck by separate button but i could not,once i checked button should checked .Here is my all code that i tried.
import React, { Component } from "react";
import { Helmet } from "react-helmet";
import config from "../Main";
import Switch from "react-switch";
import axios from "axios";
import Swal from "sweetalert2";
let authToken = localStorage.getItem("Token");
class Notification extends Component {
constructor(props) {
super(props);
this.state = {
fleet: [],
user: [],
checked: false,
isHidden: "checked",
notifications: false,
notify_critical_overspeeding: false,
notify_overspeeding: true,
notify_exceeding_fuel: true,
notify_engine_error: true,
notify_campaign_confirmation: true,
notify_campaign_start: false,
notify_car_inspection: true,
notify_insurance: false,
notify_maintenance: true,
receive_critical_overspeeding_email: true,
checkedItems: new Map()
};
this.handleChange = this.handleChange.bind(this);
this.toggleHidden = this.toggleHidden.bind(this);
}
handleChange(checked) {
this.setState({ checked });
}
toggleHidden() {
this.setState({
checked: !this.state.checked
});
}
handleChange1 = e => {
const item = e.target.name;
const isChecked = e.target.checked;
this.setState(prevState => ({
checkedItems: prevState.checkedItems.set(item, isChecked)
}));
};
async componentDidMount() {
let authToken = localStorage.getItem("Token");
try {
Promise.all([
axios({
method: "GET",
url: config.apiUrl.fleetnotification,
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: "Bearer " + JSON.parse(authToken)
}
}).then(res => {
this.setState({
notifications: res.data.notifications,
notify_critical_overspeeding: res.data.notify_critical_overspeeding,
notify_overspeeding: res.data.notify_overspeeding,
notify_exceeding_fuel: res.data.notify_exceeding_fuel,
notify_engine_error: res.data.notify_engine_error,
notify_campaign_confirmation: res.data.notify_campaign_confirmation,
notify_campaign_start: res.data.notify_campaign_start,
notify_car_inspection: res.data.notify_car_inspection,
notify_insurance: res.data.notify_insurance,
notify_maintenance: res.data.notify_maintenance
});
}),
axios({
method: "GET",
url: config.apiUrl.usernotification1,
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: "Bearer " + JSON.parse(authToken)
}
}).then(res => {
this.setState({
receive_critical_overspeeding_email:
res.data.receive_critical_overspeeding_email
});
})
]);
} catch (e) {
console.log(e);
}
}
render() {
const { fleet, user } = this.state;
const { t } = this.props;
return (
<div className="container" style={{ marginTop: "30px" }}>
<Helmet>
<title>notication_management</title>
</Helmet>
<div>
</div>
<div className="headerr" style={{ marginTop: "20px" }}>
<div className="" style={{ margin: "auto" }}>
<div className="row">
<div
class=" col-sm-6 "
style={{ marginTop: "0px", margin: "auto" }}
>
<div
// class="loml"
style={{
padding: "10px",
fontSize: "15px"
}}
>
<strong class="float-left font-weight-bold h5">
NOTIFICATION
</strong>
<small
className="float-right"
style={{ position: "relative", top: "-12px" }}
>
<label class="switch">
<input
type="checkbox"
id="togBtn"
onClick={this.toggleHidden}
/>
<div class="slider round"></div>
</label>
</small>
</div>
</div>
</div>
<br></br>
{/* All Notification List here */}
<div className="row" style={{ marginTop: "10px" }}>
<div
class=" col-sm-6 "
style={{
marginTop: "20px",
margin: "auto"
}}
>
<div
style={{
padding: "10px",
fontSize: "15px"
}}
>
<strong class="float-left font-weight-bold">
Critical overspeeding
</strong>
<small
className="float-right"
style={{ position: "relative", top: "-12px" }}
>
<Switch
onChange={e => this.handleChange1(e)}
checked={this.state.checked}
/>
</small>
</div>
<hr></hr>
<div
style={{
padding: "10px",
fontSize: "15px"
}}
>
<strong class="float-left font-weight-bold">
Overspeeding
</strong>
<small
className="float-right"
style={{ position: "relative", top: "-12px" }}
>
<Switch
onChange={e => this.handleChange1(e)}
// checked={this.state.checkedItems.get(item.name) || false}
/>
</small>
</div>
<hr></hr>
<div
style={{
padding: "10px",
fontSize: "15px"
}}
>
<strong class="float-left font-weight-bold">
Exceeding fuel consumption
</strong>
<small
className="float-right"
style={{ position: "relative", top: "-12px" }}
>
<Switch onChange={e => this.handleChange1(e)} />
</small>
</div>
<hr></hr>
</div>
</div>
{/*End All Notification List here */}
</div>
</div>
</div>
);
}
}
export default Notification;

How do I pass props from child to parent in React?

I have a dynamic table that renders a list of items that the user selects. The user can select an item from a drop down menu and then add that item to the list. As of right now I store the item list in the state of my component, which allows the table to render dynamically. What I would like is for the user to be able to click on an item in the table and be able to edit certain parts of that item, such as the quantity that they are selecting. Once the user clicks on that item from the table a Modal will appear that gets filled with the information from that specific item. My problem is that within the modal, when the user changes say the quantity of that item, I would like the Modal to close and then update the table with that value that the user changed.
Is there a way to pass this updated list of items back to the parent? Or is this not viable? and if so, what would be the right way to go about this. I will post my code below so that you guys can get a better understanding about what I'm trying to accomplish.
NOTE My modal isn't complete but I just would like to know how I can pass props back to the parent component.
Parent.js
export default Parent extends React.Component{
constructor(props){
super(props);
this.state = {
ItemList = [],
IDClicked = "",
}
AddItemHandler(){
...stuff to add to ItemList
}
RenderModal(){
let itemList = this.state.ItemList
<ItemModal items={itemList} />
}
RowClick(e){
//console.log(e.target.id)
var items = this.state.ItemList;
for(let i = 0; i < items.length; i++){
if(items[i].ID == e.target.id){
var Item = {
ID: items[i].ID,
PartName: items[i].PartName,
Quantity: items[i].Quantity
}
}
}
//console.log("Item clicked: " + JSON.stringify(Item));
this.setState({IDClicked: e.target.id})
(document.getElementById('myModal')).style.display = "block";
}
RenderTable(items){
var rows = [];
for(let i = 0; i < items.length; i++){
rows.push(
<tr style={{backgroundColor: '#B7BCDF'}} id={items[i].ID} key={i}>
<td style={{maxWidth: '20px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap'}} onClick={this.RowClick.bind(this)} id={items[i].ID}>
{items[i].PartName}
</td>
<td style={{maxWidth: '20px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap'}} onClick={this.RowClick.bind(this)} id={items[i].ID}>
{items[i].Description}
</td>
<td style={{maxWidth: '20px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap'}} onClick={this.RowClick.bind(this)} id={items[i].ID}>
{items[i].Type}
</td>
<td style={{maxWidth: '20px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap'}} onClick={this.RowClick.bind(this)} id={items[i].ID}>
{items[i].Quantity}
</td>
<td style={{maxWidth: '20px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap'}} onClick={this.RowClick.bind(this)} id={items[i].ID}>
{items[i].Units}
</td>
</tr>
)
}
return (
<div className="TableScroll2" style={{width: '99.5%', height: 'none'}}>
<table className="TableRows">
<tbody>
{rows}
</tbody>
</table>
</div>
);
}
render(){
return(
<div id="mymodal">
this.RenderModal();
</div>
<div style={{width: '50%', marginLeft: 'auto', marginRight: 'auto'}}>
<div className="ParTableContainer" style={{marginTop: '5%'}}>
<table className="PartTableHeaderContainer" style={{textAlign: 'center'}}>
<thead>
<tr>
<th style={{width: '20%'}}>Part Name</th>
<th style={{width: '20%'}}>Description</th>
<th style={{width: '20%'}}>Type</th>
<th style={{width: '20%'}}>QTY</th>
<th style={{width: '20%'}}>U/M</th>
</tr>
</thead>
</table>
</div>
{this.RenderTable(this.state.ItemList)}
</div>
<button style={{marginTop: '2%', marginBottom: '5%'}} onClick={this.AddItemHandler.bind(this)}>Add Item</button>
}
}
You cannot pass props from a child to the parent. There are however ways for a child to communicate with it's parent, which could be used to solve your problem.
The way to go is usually to use callbacks - pass a function from your parent to your child which the child can call to update the state of the parent. Here is an example that updates the parent state:
function Parent() {
const [counter, setCounter] = useState(0)
return (
<div>
Current: {state}
<Child increment={() => {
setCounter(current => current + 1)
}}}/>
</div>
)
}
function Child(props) {
return <button onClick={props.increment}>Click me</button>
}
(This example was done using hooks, which I strongly recommend learning)
Here it is without hooks:
class Parent extends Component {
constructor() {
this.state = { counter: 0 }
}
render() {
return (
<Child increment={() => {
this.setState((current) => {
return { counter: current.counter + 1 }
})
}}}/>
)
}
}
function Child(props) {
return <button onClick={props.increment}>Click me</button>
}

React App - Help me locate the cause of an infinite render loop

I'm somehow causing an infinite render loop when calling the appendModule function. I think it's being caused by the rows.js component as I recently split 4 rows out into seperate components and then imported them into one master rows.js and thats when the problem started. (note: I understand things aren't very tidy/optimal right now).
main.js
In this component I push module components into an array onclick
import React, { Component } from "react";
import Mod0 from "./modules/mod0";
import Mod1 from "./modules/mod1";
import Mod2 from "./modules/mod2";
class Main extends Component {
constructor() {
super();
this.state = {
moduleArray: this.moduleArray
};
this.moduleArray = [];
}
appendModule = x => e => {
switch (x) {
case 0:
this.moduleArray.push(
<div
key={this.moduleArray.length}
id={this.moduleArray.length}
style={{ fontSize: 0, lineHeight: 0 }}
>
<Mod0 />
</div>
);
break;
case 1:
this.moduleArray.push(
<div
key={this.moduleArray.length}
id={this.moduleArray.length}
style={{ fontSize: 0, lineHeight: 0 }}
>
<Mod1 />
</div>
);
break;
case 2:
this.moduleArray.push(
<div
key={this.moduleArray.length}
id={this.moduleArray.length}
style={{ fontSize: 0, lineHeight: 0 }}
>
<Mod2 />
</div>
);
break;
default:
}
this.setState({
moduleArray: this.moduleArray
});
};
console = () => {
return (
<div
id="console-root"
style={{ display: this.state.consoleState ? "block" : "none" }}
>
<div id="console">
<input
onClick={this.appendModule(0)}
value="Single col"
type="submit"
/>
<input
onClick={this.appendModule(1)}
value="Double col"
type="submit"
/>
<input
onClick={this.appendModule(2)}
value="Triple col"
type="submit"
/>
</div>
</div>
);
};
render() {
return (
<>
{this.console()}
<div id="email-root">
<div id="mods">{this.moduleArray}</div>
</div>
</>
);
}
}
export default Main;
mod0.js The below component is an example of the modules that contain the rows component.
import React from "react";
import Rows from "./../rows/rows";
class Mod1 extends React.Component {
render() {
return (
<table
id="Table1"
cellSpacing={0}
cellPadding={0}
border={0}
width="100%"
>
<tbody>
<tr>
<td
valign="top"
align="center"
style={{ borderCollapse: "collapse", borderWidth: 0 }}
bgcolor="#D9E1E2"
>
<table
className="Table2"
bgcolor="#FFFFFF"
cellSpacing={0}
cellPadding={0}
border={0}
width={680}
>
<tbody>
<tr>
<td
style={{ paddingTop: 24, paddingBottom: 24 }}
align="center"
>
<table
className="Table3"
align="center"
cellSpacing={0}
cellPadding={0}
border={0}
width={604}
>
<tbody>
<Rows />
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
);
}
}
export default Mod1;
rows.js The new <Rows /> component that I think is causing the problem. The rows are in an array like that so that I can add and remove them later. The problem persists if that are directly included.
import React from "react";
import Row0 from "./rows";
import Row1 from "./rows";
import Row2 from "./rows";
import Row3 from "./rows";
class Rows extends React.Component {
constructor() {
super();
this.state = {
rowArray: this.rowArray
};
this.rowArray = [
<Row0 key="0" />,
<Row1 key="1" />,
<Row2 key="2" />,
<Row3 key="3" />
];
console.log(this.rowArray);
}
render() {
return <>{this.rowArray}</>;
}
}
export default Rows;
row1.js An example of one of the individual row components imported into rows.js
import React from "react";
class Row1 extends React.Component {
render() {
return (
<tr>
<td
className="mobile-pad"
style={{
color: "#4a4a4a",
fontFamily: '"Campton", Helvetica, Arial, sans-serif',
fontSize: "26px",
lineHeight: "36px",
textAlign: "left",
paddingTop: 0,
paddingBottom: "18px"
}}
>
This is header copy
</td>
</tr>
);
}
}
export default Row1;
I believe your issue could be that instead of passing the function to onClick, you're calling the function. Try this instead:
onClick={() => { this.appendModule(0) }}
and let me know how it went
NOTE:
this uses arrow functions, introduced in ES6. You can also do
onClick={ this.appendModule.bind(this, 0) } if the former way doesn't work.

Categories