React Component keeps re-rendering/reloading - javascript

I am new to React currently doing my first react project. I can't figure out the issue here. Below is my code. User is redirected from another page to this page when they entered their search team and click search.
const Result = () => {
const navigate = useNavigate();
const [routes, setRoutes] = useState([]);
const { from, destination } = useParams();
const [departureLocation, setDepartureLocation] = useState(from);
const [destinationLocation, setDestinationLocation] = useState(destination);
const onSubmit = (e) => {
e.preventDefault();
navigate('/result/' + departureLocation + '/' + destinationLocation);
};
useEffect(() => {
refreshRoutes();
}, []);
const refreshRoutes = () => {
API.get("routes/")
.then((res) => {
setRoutes(res.data);
})
};
return (
<div className = "container mt-5">
< div className = "row" >
<div className="col-md-4">
<Form onSubmit={onSubmit} className="mt-4">
<Form.Group className="mb-3" controlId="formBasicGenre">
<Form.Label>Departure Location</Form.Label>
<Form.Control as="select"
value={departureLocation}
onChange={(e) => setDepartureLocation(e.target.value)}>
<option value="jajarkot">Jajarkot</option>
</Form.Control>
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicStarring">
<Form.Label>Destination Location</Form.Label>
<Form.Control as="select"
placeholder="Enter Destination Location"
value={destinationLocation}
onChange={(e) => setDestinationLocation(e.target.value)}>
<option value="palpa">Palpa</option>
</Form.Control>
</Form.Group>
</Form>
</div>
<div className="col-md-8 m">
<table className="table">
<thead>
<tr>
<th className="table-light" scope="col">ID</th>
<th className="table-light" scope="col">Company Name</th>
<th className="table-light" scope="col">Departure</th>
<th className="table-light" scope="col">Destination</th>
<th className="table-light" scope="col">Departure</th>
<th className="table-light" scope="col">Arrival</th>
<th className="table-light" scope="col">Departure Date</th>
<th className="table-light" scope="col">Price</th>
</tr>
</thead>
<tbody>
{routes.map((route, index) => {
return (
route.departureLocation === from && route.destinationLocation === destination ?
<tr key="">
<th className="table-light" scope="row">{route.vehicleID}</th>
<td className="table-light"> {route.name}</td>
<td className="table-light"> {route.destinationLocation}</td>
<td className="table-light"> {route.departureLocation}</td>
<td className="table-light"> {route.departureTime}</td>
<td className="table-light"> {route.arrivalTime}</td>
<td className="table-light"> {route.departureDate}</td>
<td className="table-light"> {route.price}</td>
</tr>
: null
);
})}
</tbody>
</table>
</div>
</div>
</div>
);
};
When it is redirected to result page as /result/kathmandu/gulmi it does shows the data that matches the parameter. But whenever I click on the dropdown option, the filtered data is appended in the table. I can't figure out whats causing the issue.

The only overt issue I see in your code is the React key used for the table data you are mapping. You are using the same key (key="") for each table row. You should actually be seeing tons of React warnings about duplicate keys. The issue here is that when rendering lists/arrays React uses the key in the reconciliation process, and if the key doesn't change then React bails on rerendering. As you append data to your table React can't invalidate what it previously rendered and it remains on the screen.
See Lists & Keys for more details.
The solution is to use a unique React key per table row, intrinsic id properties, like vehicleID, make for great React keys.
I suggest also running the routes array through a filter first, then mapping, it'll save the conditional rendering.
Example:
<tbody>
{routes.filter((route) =>
route.departureLocation === from && route.destinationLocation === destination
)
.map((route) => (
<tr key={route.vehicleID}>
<th className="table-light" scope="row">{route.vehicleID}</th>
<td className="table-light">{route.name}</td>
<td className="table-light">{route.destinationLocation}</td>
<td className="table-light">{route.departureLocation}</td>
<td className="table-light">{route.departureTime}</td>
<td className="table-light">{route.arrivalTime}</td>
<td className="table-light">{route.departureDate}</td>
<td className="table-light">{route.price}</td>
</tr>
)
)}
</tbody>

Related

Why is <input type='number' value={var_name}> replacing all the values in a table?

I am trying to map out a number of elements in a table and each of the elements has a specific value. Whenever i use value={inputArrival} or value={inputBurst} all the values of the specific column get update. I am attaching a screenshot. How to fix this?
Screenshot of what's happening
import React,{useState} from 'react';
import './tableEdit.css';
const EntryTable = (props) => {
const entry=props.numOfEntries;
const[inputArrival,SetinputArrival]=useState('');
const[inputBurst,SetinputBurst]=useState('');
function changeArrival(e)
{
console.log(e.target.value+"A");
/*
if(!Number(e.target.value))
return;
else*/
SetinputArrival(e.target.value);
}
function changeBurst(e)
{
console.log(e.target.value+"B");
SetinputBurst(e.target.value);
}
// console.log(entry);
var ArrayEntry=[];
for(var i=1;i<=entry;i++)
ArrayEntry.push( <tr key={i}>
<td className='row_editContent' >P{i}</td>
<td className='row_editContent'><input className='input_edit' placeholder='0' type='number' value={inputArrival} onChange={(e)=>changeArrival(e)}></input>ms</td>
<td className='row_editContent'><input className='input_edit' placeholder='0' type='number' value={inputBurst} onChange={(e)=>changeBurst(e)}></input>ms</td>
</tr>);
return (
<div>
<table className='MainTableContainer' >
<thead>
<tr >
<th className='row_editHeading'>Process</th>
<th className='row_editHeading'>Arrival Time</th>
<th className='row_editHeading'>Burst Time</th>
</tr>
</thead>
<tbody>
{ArrayEntry}
</tbody>
</table>
</div>
)
}
export default EntryTable
You are using the same single states inputArrival and inputBurst for every row entry of data in the table. Update so each is an array of strings, and update the changeArrival and changeBurst callbacks to curry an index to update. Use the mapped index to access the correct state and pass to the onChange callbacks.
const EntryTable = (props) => {
const entry = props.numOfEntries;
const [inputArrival, setInputArrival] = useState(Array(entry).fill(""));
const [inputBurst, setInputBurst] = useState(Array(entry).fill(""));
function changeArrival(index) {
return (e) => {
console.log(e.target.value + "A");
setInputArrival((values) =>
values.map((value, i) => (i === index ? e.target.value : value))
);
};
}
function changeBurst(index) {
return (e) => {
console.log(e.target.value + "B");
setInputBurst((values) =>
values.map((value, i) => (i === index ? e.target.value : value))
);
};
}
// console.log(entry);
const ArrayEntry = Array.from({ length: entry}).map((_, i) => (
<tr key={i}>
<td className="row_editContent">P{i}</td>
<td className="row_editContent">
<input
className="input_edit"
placeholder="0"
type="number"
value={inputArrival[i]}
onChange={changeArrival(i)}
/>
ms
</td>
<td className="row_editContent">
<input
className="input_edit"
placeholder="0"
type="number"
value={inputBurst[i]}
onChange={changeBurst(i)}
/>
ms
</td>
</tr>
));
return (
<div>
<table className="MainTableContainer">
<thead>
<tr>
<th className="row_editHeading">Process</th>
<th className="row_editHeading">Arrival Time</th>
<th className="row_editHeading">Burst Time</th>
</tr>
</thead>
<tbody>{ArrayEntry}</tbody>
</table>
</div>
);
};

I'm trying to put the data I'm receiving from my API into a table but nothing is displayed

I'm getting data from my API, when I make a console.log or JSON.stringify in the API data it shows without problems but when I pass the data in a table with the map, simply nothing is presented in the table. .
const [users, setUsers] = useState([]);
const loadUser = () => {
getUsers().then(data => {
if(data.error) {
console.log(data.error)
}else{
setUsers(data)
}
})
}
const inforUsers = () => {
return(
<Fragment>
<table className="table table-bordered mb-5">
<thead className="thead-dark">
<tr>
<th scope="col">Id</th>
<th scope="col">Nome</th>
<th scope="col">Email</th>
<th scope="col">role</th>
<th scope="col">createdAt</th>
</tr>
</thead>
<tbody scope="row">
{Object.keys(users).map((values, key) => (
<tr key={key}>
<td>
{values._id}
</td>
<td>
{values.name}
</td>
<td>
{values.email}
</td>
<td>
{values.role === 1? 'Admin' : 'Simples User'}
</td>
<td>
{values.createdAt}
</td>
</tr>
))}
</tbody>
</table>
</Fragment>
)
}
I think you are confused about the data you have in hand. The key is the id for each object, so if you want that data, you should access the users object by each of the keys/ids you get from Object.keys. A brief example:
{Object.keys(users).map(id => (
{users[id]._id}
))}

Switching between 2 table objects in React JS

I'm pretty new to react and I'm having trouble switching between these 2 tables. I looked at the documentation for inline conditional statements and this was all I got. I want it to switch between the tables after clicking the button.
const customer_table = (
<Table striped bordered hover>
<thead>
<tr>
<th>ID</th>
<th>Org Name</th>
<th>Status</th>
<th>More Info</th>
</tr>
</thead>
<tbody>
{customers.map(customer =>
<tr>
<td id="customer_id">{String(customer.customer_id).padStart(4, '0')}</td>
<td id="name">{customer.org_name}</td>
<td id="email">{customer.cus_status}</td>
<td><Link to={{
pathname: `/profile/${customer.customer_id}`,
query: { customer_id: `${customer.customer_id}`}
}} className="btn btn-primary">Profile</Link></td>
</tr>
)}
</tbody>
</Table>
)
return (
<td>
<div className="toggleCustomers">
<button onClick={toggleDeavtivated} >Show Deactivated Customers</button>
</div>
<ul>
{
show_deactivated ? `${deactivatedCustomer_table}`
: `${customer_table}`
}
</ul>
</td>
);
To do that you need to use state, you can read about this from this url
By using state you can update rendering by track any change from button, for example for your case:
const [firstTable, setFirstTable] = useState(true);
return (
<div>
<p>You clicked {firstTable}</p>
<button onClick={() => setFirstTable(!firstTable)}>
Click me
</button>
{ firstTable ? ${deactivatedCustomer_table}`
: `${customer_table}`
}
</div>
);

Table rows disappearing on going to the next page

I am new to react. I am using an addrow method to add the values to the table I created using {this.state.rows.map}. The table appears with the values of the input fields. However on pressing the continue button to go to the next page and then coming back from the page by pressing the back button, the row disappears.
Here is the code:
<Grid item xs={10} direction="row" alignItems="center">
<table
className="table table-bordered table-hover"
id="tab_logic"
>
<thead>
{this.state.rows.length > 0 ? (
<tr>
<th className="text-center"> # </th>
<th className="text-center"> KPI </th>
<th className="text-center"> UOM </th>
<th className="text-center"> Base </th>
<th className="text-center"> Target </th>
<th className="text-center"> Target Date </th>
<th className="text-center"> Delete Row </th>
</tr>
) : null}
</thead>
<tbody>
{this.state.rows.map((item, idx) => (
<tr id="addr1" key={idx}>
<td>{idx + 1}</td>
<td>
<input
type="text"
name="Kpi_Before"
defaultValue={Kpi_Before}
onChange={this.handleChangeRows(idx)}
className="form-control"
readOnly
/>
</td>
<td>
<input
type="text"
name="UOM_Before"
defaultValue={UOM_Before}
onChange={this.handleChangeRows(idx)}
className="form-control"
readOnly
/>
</td>
<td>
<input
type="text"
name="Base_Before"
defaultValue={Base_Before}
onChange={this.handleChangeRows(idx)}
className="form-control"
readOnly
/>
</td>
<td>
<input
type="text"
name="Target_Before"
defaultValue={Target_Before}
onChange={this.handleChangeRows(idx)}
className="form-control"
readOnly
/>
</td>
<td>
<input
type="text"
name="dateTime"
defaultValue={dateTime}
onChange={this.handleChangeRows(idx)}
className="form-control"
readOnly
size="38"
/>
</td>
<td>
The code for changes and going back and forward is this:
continue = e => {
e.preventDefault();
this.props.nextStep();
}
};
back = e => {
e.preventDefault();
this.props.prevStep();
};
handleChangeRows = idx => e => {
const { name, value } = e.target;
const rows = [...this.state.rows];
rows[idx] = {
[name]: value
};
this.setState({
rows
});
};
handleAddRow = () => {const item = {
Kpi_Before: [],
UOM_Before: "",
Base_Before: "",
Target_Before: "",
dateTime: "",
rows:[]
};
this.setState({
rows: [...this.state.rows, item]
});
}
};
nextStep = () => {
const { step } = this.state;
this.setState({
step: step + 1
});
};
//Go back to previous step
prevStep = () => {
const { step } = this.state;
this.setState({
step: step - 1
});
};
How do I keep the rows from disappearing and keep it constant on moving back and forward?
Your state re-renders when you navigate between pages or refresh which means everything inside state is lost to combat this you can either:
1) Use redux to store changes and retrieve data from there.
2) Use Context API which is the same as redux but builtin to react.
3) Consume a REST API which means have some sort of backend to store the values and get them on component mount.

How to work with multiple inputs fields with .map - ReactJS

I have an assignment to make cryptocurrenty converter using API from coinmarketcap. I have manage to retrieve data and show everything but problem is that all fields act like one field.
You can see it here:
https://repl.it/repls/IncompatibleWhirlwindHarddrive
function App() {
const [data, setData] = useState("");
const [coinValue, setCoinValue] = useState("")
const [value, setValue] = useState("")
useEffect(() => {
let url = "https://cors-anywhere.herokuapp.com/https://sandbox-api.coinmarketcap.com/v1/cryptocurrency/listings/latest"
axios
.get(url,{
headers: {
'X-CMC_PRO_API_KEY': 'c8643baa-31bf-4d31-8868-af73ce84766b'
},
})
.then(result => setData(result.data.data));
}, []);
return (
<>
<table className="table ">
<thead>
<tr>
<th>Name</th>
<th>Short Name</th>
<th>$ Value</th>
<th>Last 24h</th>
<th>Amount you own</th>
<th>$ value of your coins</th>
</tr>
</thead>
<tbody>
{Array.isArray(data) &&
data.map(objects => {
let price = objects.quote.USD.price.toFixed(2)
let Result = (function() {
return price * coinValue
});
return (
<tr key={objects.name}>
<td>{objects.name}</td>
<td>
{objects.symbol}
</td>
<td onLoad={()=>setValue(price)}>
{price}
</td>
<td style={{color: objects.quote.USD.percent_change_24h > 0 ? "green" : "red"}}>{objects.quote.USD.percent_change_24h.toFixed(2)}</td>
<td>
<input required type="number" onChange={e => setCoinValue(e.target.value)} /> <br/>
<button className="btn" disabled={!coinValue} type="submit" onClick={Result}>Submit</button>
</td>
<td>
<Result></Result>
</td>
</tr>
);
})}
</tbody>
</table>
</>
);
}
export default App;
I need to every button be disabled until there is some value in input field but on input field that goes with that button.
Also I have to show conversion for only that field that input has value when you press submit.
Thank you in advance.

Categories