I just start to learn Reactjs and have stopped with some question.
I've fetched data through axios for some API endpoint(get countries with some data like population,currencies,region etc.) and I want to sort data for some field(region or population for example).
I thought that in reactjs it will be simple to do and reactjs have some built-in things to do that. But when I've tried to do that and when I've searched answer in google I was really exposed. What is the best way to implement sorting? How can I do that?
What I've tried:
import React, { Component } from 'react';
import axios from 'axios';
import './App.css';
class App extends Component {
constructor(props){
super(props)
this.state={
countries:[],
}
}
componentDidMount(){
axios.get('https://restcountries.eu/rest/v2/all')
.then(response => {
this.setState({
countries:response.data
})
})
.catch((error) => {
console.log("error", error)
})
}
render(){
return(
<div className = 'table'>
<table>
<tbody>
<tr>
<th>Country name </th>
<th>Currencies</th>
<th>Region </th>
<th>Flag </th>
<th >Population</th>
<th>Languages</th>
</tr>
{
this.state.countries.map((country,id) => {
return(
<tr className="tableRow">
<td> {country.name}</td>
<td>{country.currencies.map((currency,i)=>{
return (
<p>
<span>{currency.name} </span>
<span>{currency.symbol} </span>
</p>
)
})} </td>
<td> {country.region}</td>
<td> <img src={country.flag} alt={country.denonym}/> </td>
<td> {country.population} </td>
<td> {country.languages.map((language)=>{
return (
<span> {language.name} </span>
)
})} </td>
</tr>
)
})
}
</tbody>
</table>
</div>
)
}
}
export default App;
Basically what you need to do is something like this:
...
this.state.countries.sort(/* Provide sort function here */).map((country,id) => {
...
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
Related
Im working on a react application using MySQL.
On my page which includes a list of serveral cars from my database i got the following error:
Server Error
TypeError: fahrzeugData.map is not a function
This error happened while generating the page. Any console logs will be displayed in the terminal window.
Source
.next\server\pages\fahrzeuge.js (34:24) # FahrzeugList
32 | </thead>
33 | <tbody className={styles.tbody}>
> 34 | {fahrzeugData.map((fzData, index) => (
| ^
35 | <tr key={index}>
36 | <td className={styles.th}>{index + 1}</td>
37 | <td className={styles.th}>{fzData.brutto}</td>
Call Stack
Function.getInitialProps
.next\server\pages\_document.js (150:43)
My js file looks like this:
import React from "react";
import Header from "./Header";
import Link from "next/link";
import { useRouter } from "next/router";
import styles from "../styles/FahrzeugList.module.css";
import axios from "axios";
function FahrzeugList({ fahrzeugData }) {
const router = useRouter();
const deleteFahrzeug = async (id) => {
let fahrzeugliste_t5 = await axios.delete(`http://localhost:3000/api/fahrzeug/${id}`);
router.push("/fahrzeuge");
};
return (
<>
<Header />
<table className={styles.table}>
<thead className={styles.thead}>
<tr>
<th className={styles.th}>FahrzeugId</th>
<th className={styles.th}>brutto</th>
<th className={styles.th}>erstzulassung</th>
<th className={styles.th}>fahrzeugnummer</th>
<th className={styles.th}>kilometer</th>
<th className={styles.th}>modelljahr</th>
<th className={styles.th}>netto</th>
<th className={styles.th}>reserviert</th>
<th className={styles.th}>sitzer</th>
<th className={styles.th}>sonstiges</th>
<th className={styles.th}>tuev</th>
<th className={styles.th}>Actions</th>
</tr>
</thead>
<tbody className={styles.tbody}>
{fahrzeugData.map((fzData, index) => (
<tr key={index}>
<td className={styles.th}>{index + 1}</td>
<td className={styles.th}>{fzData.brutto}</td>
<td className={styles.th}>{fzData.erstzulassung}</td>
<td className={styles.th}>{fzData.fahrzeugnummer}</td>
<td className={styles.th}>{fzData.kilometer}</td>
<td className={styles.th}>{fzData.modelljahr}</td>
<td className={styles.th}>{fzData.netto}</td>
<td className={styles.th}>{fzData.reserviert}</td>
<td className={styles.th}>{fzData.sitzer}</td>
<td className={styles.th}>{fzData.sonstiges}</td>
<td>
<button
className={styles.delete}
onClick={() => deleteFahrzeug(fzData.fz_id)}
>
Delete
</button>
<button className={styles.update}>
<Link href={`/fahrzeuge/${fzData.fz_id}`}>Update</Link>
</button>
</td>
</tr>
))}
</tbody>
</table>
<div className={styles.addFahrzeugCenter}>
<button className={styles.addFahrzeug}>
<Link href={`/addFahrzeug`}>addFahrzeug</Link>
</button>
</div>
</>
);
}
export default FahrzeugList;
Here is the js code where the FahrzeugList is used:
import FahrzeugList from "../components/FahrzeugList";
function fahrzeuge({ fahrzeugliste_t5 }) {
console.log("fahrzeugliste_t5", fahrzeugliste_t5);
return (
<div>
<FahrzeugList fahrzeugData={fahrzeugliste_t5} />
</div>
);
}
export async function getServerSideProps() {
const res = await fetch("http://localhost:3000/api/fahrzeug");
const fahrzeugliste_t5 = await res.json();
return {
props: { fahrzeugliste_t5 },
};
}
export default fahrzeuge;
And my database looks basically like this:
Adding new Cars to the list works perfectly from a different screen but displaying the list doesnt work. The Documentation for .map() function didnt help me.
I'm trying to figure out why I'm getting Cannot destructure property 'id' of 'this.props.customer' as it is undefined. error. My code seems to be correct from the looks of it but despite this fact, I'm still getting the aforementioned error. Is there something minuscule that I'm overlooking?
Here's CustomerList.js file:
import React, { Component } from "react";
import Customer from "./Customer";
class CustomerList extends Component {
render() {
const customers = this.props.customers;
return(
<div className="data">
<table className="ui celled table">
<thead>
<tr>
<th style={{ width: '50px', textAlign: 'center' }}>#</th>
<th>Name</th>
<th>E-mail</th>
<th style={{ width: '148px' }}>Action</th>
</tr>
</thead>
<tbody>
{
customers.map(customer => {
return <Customer customer={customer} key={customer.id} />;
})
}
<Customer/>
</tbody>
</table>
</div>
);
}
}
export default CustomerList;
Here's Customer.js:
import React, { Component } from 'react';
class Customer extends Component {
render() {
const { id, first_name, last_name, email } = this.props.customer;
return (
<tr>
<td style={{ textAlign: 'center' }}>{id}</td>
<td>{`${first_name} ${last_name}`}</td>
<td>{email}</td>
<td>
<button className="mini ui blue button">Edit</button>
<button className="mini ui red button">Delete</button>
</td>
</tr>
);
}
}
export default Customer;
Below the map part you have a single
<Customer/>
This call to the Customer component has no parameters, so customer is undefined. That is why you get the error.
I'm having a problem wrapping my head around the .map() function as it relates to ReactJS. In practice, I have a table onto which I can add rows, but deleting a row by passing the index of the row is just not working. Here's what I have; can anyone clear up what I'm doing wrong?
import React from 'react';
import { render } from 'react-dom';
class CommentList extends React.Component {
constructor(props) {
super(props);
this.state = {
comments: []
};
this.handleCommentDelete = this.handleCommentDelete.bind(this);
}
handleCommentDelete(i) {
alert('i = ' + i);
let comments = [...this.state.comments];
comments.splice(i, 1);
this.setState({
comments: comments
});
}
render() {
return (
<table className="commentList">
<thead>
<tr>
<th>Name</th>
<th>Phone</th>
<th>Email</th>
<th></th>
</tr>
</thead>
<tbody>
{
this.props.data.map((comment, i) => {
return (
<tr className="comment" key={i}>
<td className="commentId">{comment.Id}</td>
<td className="commentName">{comment.Name}</td>
<td className="commentPhone">{comment.Phone}</td>
<td className="commentEmail">{comment.Email}</td>
<td className="commentCRUD">
<a onClick={(i) => this.handleCommentDelete(i)}>
<i className="fa fa-trash" />
</a>
</td>
</tr>
);
})
}
</tbody>
</table>
);
}
}
export default CommentList;
Thanks in advance!
You are passing the index i, not the right way. Also i would prefer to pass id rather than index. Here is how you can do that:
import React from 'react';
import { render } from 'react-dom';
class CommentList extends React.Component {
constructor(props) {
super(props);
this.state = {
comments: []
};
this.handleCommentDelete = this.handleCommentDelete.bind(this);
}
handleCommentDelete(id) {
let comments = this.state.comments.filter(comment => comment.id !== id);
this.setState({
comments: comments
});
}
render() {
return (
<table className="commentList">
<thead>
<tr>
<th>Name</th>
<th>Phone</th>
<th>Email</th>
<th></th>
</tr>
</thead>
<tbody>
{
this.props.data.map(comment => {
return (
<tr className="comment" key={comment.Id}>
<td className="commentId">{comment.Id}</td>
<td className="commentName">{comment.Name}</td>
<td className="commentPhone">{comment.Phone}</td>
<td className="commentEmail">{comment.Email}</td>
<td className="commentCRUD">
<a onClick={() => this.handleCommentDelete(comment.Id)}>
<i className="fa fa-trash" />
</a>
</td>
</tr>
);
})
}
</tbody>
</table>
);
}
}
export default CommentList;
Hope this works for you.
I am building web application using railway api, on submitting train number I am trying to display data but getting the above error. Actually I used if else condition on fetching data.
below is the code.
import React, { Component } from "react";
export default class TrainRoute extends Component {
constructor(props) {
super(props);
this.state = { trainNumber: "", trainRouteList: "" };
this.onChange = this.onChange.bind(this);
this.onSubmitForm = this.onSubmitForm.bind(this);
}
onChange(e) {
this.setState({ [e.target.id]: e.target.value } );
}
onSubmitForm(e) {
e.preventDefault();
fetch(
`https://api.railwayapi.com/v2/route/train/${
this.state.trainNumber
}/apikey/sch9lj34uy/`
)
.then(res => res.json())
.then(data => {
this.setState({ trainRouteList: data }, () =>
console.log(this.state.trainRouteList)
);
});
this.setState({ trainNumber: "" });
}
render() {
const { trainRouteList } = this.state;
if (!trainRouteList) {
const list = <div>No Trains Details to display</div>;
const route = <div>No Routes to display</div>;
} else {
const list = (
<div>
<table>
<tbody>
<tr>
<td>Train Name :</td>
<td> {trainRouteList.train.name} </td>
</tr>
<tr>
<td>Train Number :</td>
<td> {trainRouteList.train.number} </td>
</tr>
<tr>
<td>Class :</td>
<td>
{trainRouteList.train.classes.map(trainClass => (
<span key={trainClass.code}>{trainClass.code},</span>
))}{" "}
</td>
</tr>
</tbody>
</table>
</div>
);
const route = trainRouteList.route.map(routeInfo => (
<table>
<tbody>
<tr>
<td>Station :</td>
<td> {routeInfo.station.name} </td>
</tr>
<tr>
<td>Departure Time :</td>
<td> {routeInfo.schdep} </td>
</tr>
<tr>
<td>Arrival Time :</td>
<td> {routeInfo.scharr} </td>
</tr>
</tbody>
</table>
));
}
return (
<div>
<div className="container">
<form
onSubmit={this.onSubmitForm}
className="col-md-8 col-md-offset-4"
>
<div className="row">
<div className="col-md-3">
<input
type="number"
className="form-control input-lg"
placeholder="Train Number"
id="trainNumber"
value={this.state.trainNumber}
onChange={this.onChange}
/>
</div>
<div className="col-md-1">
<button type="submit" className="btn btn-warning btn-lg">
Check Route
</button>
</div>
</div>
</form>
</div>
<div className="card card-fluid">
<div className="container">
{list}
<h3>Train Route</h3>
{route}
</div>
</div>
</div>
);
}
}
Getting error at list and route in render method. Can Anyone tell
me why I am getting this error as I tried all possible solution
Its because list and route are block level variable and you are trying to access them outside of block.
Solution is, Define those variables outside then update the value in if and else block, by that way we can access anywhere inside render method. Like this:
render() {
const { trainRouteList } = this.state;
let list, route;
if (!trainRouteList) {
list = <div>No Trains Details to display</div>;
route = <div>No Routes to display</div>;
} else {
list = ....;
route = ....;
}
im trying to add a row to a table, on a click event. Here is my component:
import React, { Component } from 'react';
import PageContent from 'components/PageContent';
import { IBox, IBoxTitle, IBoxContent } from 'components/IBox';
import IBoxTools from 'components/IBoxTools';
import Table from 'components/Table';
export default class SalesChannelsPage extends Component {
constructor(props) {
super(props);
this.addRow = this.addRow.bind(this);
}
render() {
return (
<PageContent header="Salgskanaler">
<IBox>
<IBoxTitle>
Salgskanaler
<IBoxTools icon="fa fa-plus" title="Tilføj salgskanal" handleClick={() => this.addRow()}/>
</IBoxTitle>
<IBoxContent>
<Table>
<thead>
<tr>
<td className="channel-name">Navn</td>
<td className="channel-description">Beskrivelse</td>
<td className="channel-btn"></td>
</tr>
</thead>
<tbody>
</tbody>
</Table>
</IBoxContent>
</IBox>
</PageContent>
);
}
addRow() {
console.log('add row')
}
}
So everytime i click the button, a new row should be added, and it should be possible to add as many rows to the list as possible. here is the row i want to add.
i realize that i could make an array in state and just put it there, but i have learned that only the data should be contained in the state. Some help would be much appreciated.
Thx
<tr>
<td className="channel-name">
<input className="form-control input-sm" type="text" placeholder="Navn..." />
</td>
<td className="channel-description">
<input className="form-control input-sm" type="text" placeholder="Beskrivelse..." />
</td>
<td className="channel-btn">
<div>
<div className="btn btn-xs btn-danger"><span className="fa fa-times"></span></div>
<div className="btn btn-xs btn-primary"><span className="fa fa-floppy-o"></span></div>
</div>
</td>
</tr>
So as Matthew Herbst said, this is what state is for. Presumably those rows need to display some kind of data. You shouldn't be storing the HTML/JSX in the array, but you should be storing the data used to construct the list in the array. This is what is great about React. You declare how the UI should be presented based on the underlying data. Then you just manipulate the data. So first you need an array in your state that represents the list. Also, you don't need to declare your addRow handler as being returned by a function. It is a function. Just pass the function without invoking it by excluding the () parentheses. Finally, you map over the array, returning the rows. Obviously this is all kind of dump without data, but it is immediately clear what data you want in the rows. So it should look something like this:
import React, { Component } from 'react';
import PageContent from 'components/PageContent';
import { IBox, IBoxTitle, IBoxContent } from 'components/IBox';
import IBoxTools from 'components/IBoxTools';
import Table from 'components/Table';
export default class SalesChannelsPage extends Component {
constructor(props) {
super(props);
this.addRow = this.addRow.bind(this);
this.state = {
rows: []
}
}
render() {
return (
<PageContent header="Salgskanaler">
<IBox>
<IBoxTitle>
Salgskanaler
<IBoxTools icon="fa fa-plus" title="Tilføj salgskanal" handleClick={this.addRow}/>
</IBoxTitle>
<IBoxContent>
<Table>
<thead>
<tr>
<td className="channel-name">Navn</td>
<td className="channel-description">Beskrivelse</td>
<td className="channel-btn"></td>
</tr>
</thead>
<tbody>
{this.state.rows.map(row => <tr></tr>)}
</tbody>
</Table>
</IBoxContent>
</IBox>
</PageContent>
);
}
addRow() {
var nextState = this.state;
nextState.rows.push('placeholder');
this.setState(nextState);
}
}
Again I am just pushing the text placeholder to the end of the array each time because I don't know what data you want in there. But this will keep generate empty <tr> tags for you on each push of the button.