I'm building a MERN stack app that fetches data about college classes and render it in a table. The CoursesTable.js component looks like this:
import React, { useState, useEffect } from 'react';
import { Table } from 'react-materialize';
import axios from 'axios';
const CoursesTable = () => {
const [courses, setCourses] = useState([]);
useEffect(() => {
const fetchData = async () => {
const coursesData = await axios.get('http://localhost:8001/')
setCourses(coursesData.data)
}
fetchData()
}, [])
return (
<Table>
<thead>
<tr>
<th data-field="course-name">
Name
</th>
<th data-field="course-prof">
Prof.
</th>
<th data-field="course-code">
Code
</th>
</tr>
</thead>
<tbody>
{
courses.length >= 1
? courses.map(course =>
<tr key={course._id}>
<td>
{course.name}
</td>
<td>
{course.prof}
</td>
<td>
{course.code}
</td>
</tr>
)
: <tr>
<td>There is no course</td>
</tr>
}
</tbody>
</Table>
);
}
export default CoursesTable;
I use conditional rendering so that if courses is empty, a message that goes like There is no course is displayed. When the array is full, the data is rendered in table rows.
My issue is: when courses is full and CoursesTable.js is rendered, the There is no course message always comes up for just a few milliseconds before being replaced with the data.
How can I fix this? Thanks for your help guys!
You could have a conditional check in place, e.g.:
import React, { useState, useEffect } from 'react';
import { Table } from 'react-materialize';
import axios from 'axios';
const CoursesTable = () => {
const [courses, setCourses] = useState([]);
const [isLoading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
const coursesData = await axios.get('http://localhost:8001/')
setCourses(coursesData.data)
setLoading(false);
}
fetchData()
}, [])
if(isLoading) { return <div> Loading ... </div> };
return (
<Table>
<thead>
<tr>
<th data-field="course-name">
Name
</th>
<th data-field="course-prof">
Prof.
</th>
<th data-field="course-code">
Code
</th>
</tr>
</thead>
<tbody>
{
courses.length >= 1
? courses.map(course =>
<tr key={course._id}>
<td>
{course.name}
</td>
<td>
{course.prof}
</td>
<td>
{course.code}
</td>
</tr>
)
: <tr>
<td>There is no course</td>
</tr>
}
</tbody>
</Table>
);
}
export default CoursesTable;
Related
My main component
Here I'm fetching data from backend and receiving it well. Here how it looks like.
And now I want to sort them by their properties like step 1, step 2. I'm using React query to fetch data but I'm not sure how to sort it. Also, I already have sorting functions. But, I don't know how to change data based on the sorting atribute.
.
import React, { useEffect, useState } from "react";
import useFetchTable from "../../../../api/table/useFetchTable";
const TableList = () => {
const { data: response, status, isLoading } = useFetchTable();
// const [sortField, setSortField] = useState("");
// const [order, setOrder] = useState("asc");
// const handleSortingChange = (accessor) => {
// const sortOrder =
// accessor === sortField && order === "desc" ? "asc" : "desc";
// setSortField(accessor);
// setOrder(sortOrder);
// handleSorting(accessor, sortOrder);
// };
// const handleSorting = (sortField, sortOrder) => {
// if (sortField) {
// const sorted = [...data].sort((a, b) => {
// if (a[sortField] === null) return 1;
// if (b[sortField] === null) return -1;
// if (a[sortField] === null && b[sortField] === null) return 0;
// return (
// a[sortField].toString().localeCompare(b[sortField].toString(), "en", {
// numeric: true,
// }) * (sortOrder === "asc" ? 1 : -1)
// );
// });
// setData(sorted);
// }
// };
if (status === "error") {
return "Error";
}
if (isLoading) {
return "Loading...";
}
console.log(response);
const Print = ({ children }) => {
return (
<span className="text-xs bg-blue-100 rounded-full px-2 py-0.5 ml-2">
{children}%
</span>
);
};
return (
<div>
<table>
<thead className="border-b-2">
<tr>
<th className="py-1">Product Name</th>
<th>Purchases</th>
<th>US</th>
<th>Ch Step 1</th>
<th>Ch Step 2</th>
<th>CVR</th>
<th> 1</th>
<th>Upsell 2</th>
<th>Upsell 3</th>
</tr>
</thead>
<tbody>
{response.data?.map((row, idx) => (
<tr key={idx}>
<td>{row.name}</td>
<td>
{row.purchases[0]} <Print>{row.purchases[1]}</Print>
</td>
<td>
{row.unique_sessions} <Print>100</Print>
</td>
<td>
{row.checkout_step_1[0]} <Print>{row.checkout_step_1[1]}</Print>
</td>
<td>
{row.checkout_step_2[0]} <Print>{row.checkout_step_2[1]}</Print>
</td>
<td>
<Print>{`${row["cvr_%"]}`}</Print>
</td>
<td>
{row.upsell_1_takes[0]} <Print>{row.upsell_1_takes[1]}</Print>
</td>
<td>
{row.upsell_2_takes[0]} <Print>{row.upsell_2_takes[1]}</Print>
</td>
<td>
{row.upsell_3_takes[0]} <Print>{row.upsell_3_takes[1]}</Print>
</td>
</tr>
))}
</tbody>
</table>
TableList
{/* {data?.map((el) => {
el.title;
})} */}
</div>
);
};
export default TableList;
So for sorting based on your column header you can create a function to handle that onClick of the particular header. Like in the below code I have used the firstName column for sorting. On clicking the first name header it will trigger the function sortByFirstName and added the sort functionality in it and updated the state of the setTableData . Hope this helps.
import React, { useEffect, useState } from 'react'
import { useQuery } from 'react-query'
import './style.css'
function Example () {
const [sorted, setSorted] = useState({ sorted: "fname", reversed: false });
const [tableData, setTableData] = useState([])
const { data } = useQuery({
queryKey: ['repoData'],
queryFn: () =>
fetch('https://dummyjson.com/users?limit=10').then(
(res) => res.json(),
),
})
useEffect(() => {
if (data) {
setTableData(data?.users)
}
}, [data])
const sortByFirstName = () => {
setSorted({ sorted: "fname", reversed: !sorted.reversed })
const tableDataCopy = [...tableData];
tableDataCopy.sort((a, b) => {
let fnameA = a.firstName.toLowerCase();
let fnameB = b.firstName.toLowerCase();
if (sorted.reversed) {
return fnameB.localeCompare(fnameA)
}
return fnameA.localeCompare(fnameB)
})
setTableData(tableDataCopy)
}
return (
<div className='h-full w-full'>
<table className='data' cellspacing="0" cellpadding="0">
<thead>
<tr>
<th onClick={ sortByFirstName }>First Name</th>
<th >Last Name</th>
<th >Gender</th>
<th >Email</th>
<th >Bloodgroup</th>
<th >Age</th>
<th > Weight</th>
<th >Maiden Name</th>
<th >Phone</th>
</tr>
</thead>
<tbody>
{ tableData?.map((row, idx) => (
<tr key={ idx }>
<td>{ row.firstName }</td>
<td>
{ row.lastName }
</td>
<td>
{ row.gender }
</td>
<td>
{ row.email }
</td>
<td>
{ row.bloodGroup }
</td>
<td>
{ row.age }
</td>
<td>
{ row.weight }
</td>
<td>
{ row.maidenName }
</td>
<td>
{ row.phone }
</td>
</tr>
)) }
</tbody>
</table>
</div>
)
}
export default Example
I want to fetch the username of those people who order under the user ID. Is it possible to grab the owner of the id and render it to the UI using userId? instead of rendering the actual userId.
It came from different schema in database,
import React, { useEffect, useState } from 'react'
import { format } from 'timeago.js'
import { userRequest } from '../../requestMethod'
import './Widgetlg.css'
const WidgetLg = () => {
const Button = ({ type }) => {
return <button className={'widgetLgButton ' + type}>{type}</button>
}
const [orders, setOrders] = useState([])
useEffect(() => {
const getOrders = async () => {
//this is just a shorcut api
try {
const res = await userRequest.get('orders')
setOrders(res.data)
console.log(res.data)
} catch (error) {
console.log(error)
}
}
getOrders()
}, [])
return (
<div className="widgetLg">
<h3 className="widgetLgTitle">Latest Transactions</h3>
<table className="widgetTable">
<tr className="widgetLgTr">
<th className="widgetLgTh">Customer</th>
<th className="widgetLgTh">Date</th>
<th className="widgetLgTh">Amount</th>
<th className="widgetLgTh">Status</th>
</tr>
{orders.map((order) => (
<tr className="widgetLgTr">
<td className="widgetLgUser">
<span className="WidgetLgName"> {order.userId} </span>
</td>
<td className="widgetLgDate"> {format(order.createdAt)} </td>
<td className="widgetLgAmmount">P {order.amount} </td>
<td className="widgetLgStatus">
<Button type={order.status} />
</td>
</tr>
))}
</table>
</div>
)
}
export default WidgetLg
How can I fetch and render the owner of the given userId?
UI
As Best as can tell you need to get a joint document or join query and create a simple endpoint that you can call at once at the ui side using axios.
Before posting I always google, youtube, forums or try to figure it by myself or even check other people questions that are similar but I'm stuck sadly.
So I'm using firestore database, the user can create a "student" and the data is the firestore is saved like this:
It saves the course, Name, school, and the UID of the person that create it. So far I have no problems importing that information to the firestore now the issue is to bring it back in a table, I do not understand why is not being printed.
The console Log is printing all the students 1 by 1 + all the students in the array (is cause is going through all the info)
Now as you can see the table is empty! and I do not understand WHY!!! Very frustrated
This are snips of the code that are relevant:
DB part:
useEffect(() => {
db.collection('usuarios').doc(user.uid).collection('estudiantes')
.get().then((snapshot) => {
(snapshot.forEach(doc => {
const data = doc.data();
estudiantes.push(data)
console.log(doc.data());
console.log(estudiantes)
}))
})
}, []);
Map/Rendering
<tbody>
{estudiantes.map((e) => (
<tr >
<td>
<input onChange = {(event) => {
let checked = event.target.checked;
}}
type="checkbox" checked = "">
</input>
</td>
<td >{e.name}</td>
<td >{e.school}</td>
<td >{e.grade}</td>
<td></td>
</tr>
))}
</tbody>
Whole Code:
import React, { useState, useEffect } from 'react'
import { auth, db } from './firebase';
import "./ListadoEstudiantes.css"
import data from "./mock-data.json"
import { useHistory } from 'react-router-dom';
import { Checkbox } from '#material-ui/core';
function ListadoEstudiantes({user}) {
const [contacts, setContacts] = useState(data);
const history = useHistory("");
const crearEstudiante = () => {
history.push("/Crear_Estudiante");
}
const realizarPedidos = () => {
history.push("/Crear_Pedidos");
}
const estudiantes = [];
useEffect(() => {
db.collection('usuarios').doc(user.uid).collection('estudiantes')
.get().then((snapshot) => {
(snapshot.forEach(doc => {
const data = doc.data();
estudiantes.push(data)
console.log(doc.data());
console.log(estudiantes)
}))
})
}, []);
return (
<div className="listadoEstudiantes">
<div className="estudiantes_container">
<h1 className = "estudiantes_container_h1">Listado de estudiantes</h1>
<button onClick={crearEstudiante} className = "crear_estudiante_boton">Crear Estudiantes</button>
<h3 className = "estudiantes_container_h3">*Para realizar su pedido seleccione a los estudiantes</h3>
<div className ="tableContainer">
<table>
<thead>
<tr className="Lista">
<th>
<input type="checkbox"></input>
</th>
<th>Nombre</th>
<th>Colegio</th>
<th>Grado</th>
<th>Accion</th>
</tr>
</thead>
<tbody>
{estudiantes.map((e) => (
<tr >
<td>
<input onChange = {(event) => {
let checked = event.target.checked;
}}
type="checkbox" checked = "">
</input>
</td>
<td >{e.name}</td>
<td >{e.school}</td>
<td >{e.grade}</td>
<td></td>
</tr>
))}
</tbody>
</table>
</div>
<div className="space" />
<button onClick={realizarPedidos} className = "crear_estudiante_boton">Realizar Pedidos</button>
<div className="space" />
</div>
</div>
)
}
export default ListadoEstudiantes
I think that's it, the user is from the Firestore database also the data that I'm importing is a fake data that I used to test the table (and renders with no issues) that can be ignored.
This is how it looks on the fake data and how it should look with the real data (THAT DOESN'T WORK! :'3)
estudiantes should be a local state of the component. Therefore, it needs to be captured as a state and use it for table data rendering as follows.
setEstudiantes is a setState function which updates the state asynchornously. Therefore, in order to check the updated state, you need to have the console.log("estudiantes: ", estudiantes) inside the render method (not after setEstudiantes(tempData)). Otherwise, you won't be able to see the updated state.
import React, { useState, useEffect } from "react";
import { auth, db } from "./firebase";
import "./ListadoEstudiantes.css";
import data from "./mock-data.json";
import { useHistory } from "react-router-dom";
import { Checkbox } from "#material-ui/core";
function ListadoEstudiantes({ user }) {
const [contacts, setContacts] = useState(data);
const [estudiantes, setEstudiantes] = useState([]);
const history = useHistory("");
const crearEstudiante = () => {
history.push("/Crear_Estudiante");
};
const realizarPedidos = () => {
history.push("/Crear_Pedidos");
};
useEffect(() => {
db.collection("usuarios")
.doc(user.uid)
.collection("estudiantes")
.get()
.then((snapshot) => {
const tempData = [];
snapshot.forEach((doc) => {
const data = doc.data();
tempData.push(data);
console.log(doc.data());
console.log("Temp Data: ", tempData);
});
setEstudiantes(tempData);
});
}, []);
console.log("estudiantes: ", estudiantes);
return (
<div className="listadoEstudiantes">
<div className="estudiantes_container">
<h1 className="estudiantes_container_h1">Listado de estudiantes</h1>
<button onClick={crearEstudiante} className="crear_estudiante_boton">
Crear Estudiantes
</button>
<h3 className="estudiantes_container_h3">
*Para realizar su pedido seleccione a los estudiantes
</h3>
<div className="tableContainer">
<table>
<thead>
<tr className="Lista">
<th>
<input type="checkbox"></input>
</th>
<th>Nombre</th>
<th>Colegio</th>
<th>Grado</th>
<th>Accion</th>
</tr>
</thead>
<tbody>
{estudiantes.map((e) => (
<tr>
<td>
<input
onChange={(event) => {
let checked = event.target.checked;
}}
type="checkbox"
checked=""
></input>
</td>
<td>{e.name}</td>
<td>{e.school}</td>
<td>{e.grade}</td>
<td></td>
</tr>
))}
</tbody>
</table>
</div>
<div className="space" />
<button onClick={realizarPedidos} className="crear_estudiante_boton">
Realizar Pedidos
</button>
<div className="space" />
</div>
</div>
);
}
export default ListadoEstudiantes;
The problem is I don't know how to put effect from parent component to child component...
I'm creating sorting function.
tableSort = (event, sortKey) => {
const {data} = this.state;
data.sort((a,b) => a[sortKey].localeCompare(b[sortKey]) )
this.setState({ data })
}
and then I'm trying to render that in my table
render() {
const {data} = this.state
return (
<>
<Table>
<Thead>
<Tr>
<Th onClick={e => this.tableSort(e, 'pool number')}>Pool Number</Th>
<Th>Sender</Th>
<Th>Not Routed Reason</Th>
<Th>Sent Date Time</Th>
<Th>Requested Delivery Report Mask Text</Th>
<Th>Delivery Report Received Date Time</Th>
<Th>isUnicode</Th>
<Th>MessageUUID</Th>
</Tr>
</Thead>
{this.renderData(data)}
</Table>
</>
)
}
The child component is called in this component and it locks like this..
import React from 'react'
import { Tbody, Tr, Td } from 'react-super-responsive-table'
const TablePageList = ({data}) => {
const {poolNumber, sender, notRoutedReason, sentDateTime, requestedDeliveryReportMaskText,
deliveryReportReceivedDateTime, isUnicode, messageUUID} = data
return (
<Tbody>
<Tr>
<Td>{poolNumber}</Td>
<Td>{sender}</Td>
<Td>{notRoutedReason}</Td>
<Td>{sentDateTime}</Td>
<Td>{requestedDeliveryReportMaskText}</Td>
<Td>{deliveryReportReceivedDateTime}</Td>
<Td>{isUnicode}</Td>
<Td>{messageUUID}</Td>
</Tr>
</Tbody>
)
}
export default TablePageList
So how can I access and sort my Td from Th?
You should call the child component from parent. You didn't call any child component.
Try below code.
import child compenent url.
import TablePageList from "./TablePageList";
And then keep state data.
this.state = {
data:[]
}
Also change function setState and order data.
tableSort = (event, sortKey) => {
const {data} = this.state;
data.sort((a,b) => a[sortKey].localeCompare(b[sortKey]) )
this.setState({ data: data })
}
And call TablePageList component below </Thead>
render() {
const { data } = this.state;
return (
<Table>
<Thead>
<Tr>
<Th onClick={e => this.tableSort(e, "pool number")}>
Pool Number
</Th>
<Th>Sender</Th>
<Th>Not Routed Reason</Th>
<Th>Sent Date Time</Th>
<Th>Requested Delivery Report Mask Text</Th>
<Th>Delivery Report Received Date Time</Th>
<Th>isUnicode</Th>
<Th>MessageUUID</Th>
</Tr>
</Thead>
{data.map(element => {
<TablePageList data={element}></TablePageList>;
})}
</Table>
);
}
And then you get data and fill it.
const TablePageList = ({ data }) => {
return (
<Tbody>
<Tr>
<Td>{data.poolNumber}</Td>
<Td>{data.sender}</Td>
<Td>{data.notRoutedReason}</Td>
<Td>{data.sentDateTime}</Td>
<Td>{data.requestedDeliveryReportMaskText}</Td>
<Td>{data.deliveryReportReceivedDateTime}</Td>
<Td>{data.isUnicode}</Td>
<Td>{data.messageUUID}</Td>
</Tr>
</Tbody>
);
};
I'm working on a project, and I would like to display some data from my firebase database,
I can show some of them, but I want to display the rest of the data of my "listClients" on a box, linked to the checkbox with the id.
listClients.js it's where i map the data from the db
import React, { Component } from "react";
import * as firebase from "firebase";
import { Table, InputGroup } from "react-bootstrap";
class ListClients extends React.Component {
state = {
loading: true
};
componentWillMount() {
const ref = firebase.database().ref("listClients");
ref.on("value", snapshot => {
this.setState({ listClients: snapshot.val(), loading: false });
});
}
render() {
if (this.state.loading) {
return <h1>Chargement...</h1>;
}
const clients = this.state.listClients.map((client, i) => (
<tr key={i}>
<td>
<input id={client.id} type="checkbox" onChange={this.cbChange} />
</td>
<td>{client.nom}</td>
<td>{client.prenom}</td>
</tr>
));
const clientsAdresses = this.state.listClients.map((clientAdresse, i) => (
<tr key={i}>
<td id={clientAdresse.id}>{clientAdresse.adresse}</td>
</tr>
));
return (
<>
<Table className="ContentDesign" striped bordered hover>
<thead>
<tr>
<th></th>
<th>First Name</th>
<th>Last Name</th>
</tr>
</thead>
<tbody>{clients}</tbody>
</Table>
<Table className="ContentDesign" striped bordered hover>
<thead>
<tr>
<th>Adresse : </th>
</tr>
</thead>
<tbody>{clientsAdresses}</tbody>
</Table>
</>
);
}
}
export default ListClients;
my data :
I only want the "adresse" of the id where the checkbox is check
Thank you
ERROR :
To retrieve the adresse from the database then use the following code:
componentWillMount() {
const ref = firebase.database().ref("listClients");
ref.on("value", snapshot => {
snapshot.forEach((subSnap) => {
let address = subSnap.val().adresse;
});
});
}
First add a reference to node listClients the using forEach you can iterate and retrieve the adresse
If you want to get the adresse according to the id, then you can use a query:
const ref = firebase.database().ref("listClients").orderByChild("id").equalTo(0);