Display a table in React using different components - reactjs

I'm just starting to learn React and what I'm trying to do is to display a table. I'm doing it using 3 components: App.js, DisplayTable.js, and TableRows.js. The reason I'm doing it this way is that later on, I will need certain rows of the table to be displayed subject to different conditions. I don't get any error messages, but the table is not being displayed. This is my code:
App.js:
import Form from './components/Form'
import { useState } from 'react'
import TableDisplay from './components/TableDisplay'
const App = () => {
const [rows, setRows] = useState([
{
id:1,
description:'',
semester:'',
prefix:'ENG',
number:'368/371',
grade:'',
editing:''
},
{
id:2,
description:'',
semester:'',
prefix:'',
number:'',
grade:'',
editing:''
},
{
id:3,
description:'',
semester:'',
prefix:'',
number:'',
grade:'',
editing:''
},
])
return (
<div className="container">
<Form/>
<TableDisplay rows={rows}/>
</div>
);
}
export default App;
TableDisplay.js:
import TableRows from "./TableRows"
const TableDisplay = ({rows}) => {
return (
<>
{rows.map((row) => {
<TableRows key={row.id} row={row}/>
})}
</>
)
}
export default TableDisplay
TableRows.js:
import React from 'react'
const TableRows = ({row}) => {
return (
<div className="container">
<table className="table table-striped">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Description</th>
<th scope="col">Semester</th>
<th scope="col">Prefix</th>
<th scope="col">Number</th>
<th scope="col">Grade</th>
<th scope="col">Editing</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">{row.id}</th>
<td>{row.description}</td>
<td>{row.semester}</td>
<td>ENG</td>
<td>368/371</td>
<td>{row.grade}</td>
<td><button type="button" className="btn btn-warning">Edit</button></td>
</tr>
<tr>
<th scope="row">{row.id}</th>
<td>{row.description}</td>
<td>{row.semester}</td>
<td>ENG</td>
<td>368/371</td>
<td>{row.grade}</td>
<td><button type="button" className="btn btn-warning">Edit</button></td>
</tr>
<tr>
<th scope="row">{row.id}</th>
<td>{row.description}</td>
<td>{row.semester}</td>
<td>ENG</td>
<td>368/371</td>
<td>{row.grade}</td>
<td><button type="button" className="btn btn-warning">Edit</button></td>
</tr>
</tbody>
</table>
</div>
)
}
export default TableRows

You should remove bracket
const TableDisplay = ({ rows }) => {
return (
<>
{rows.map((row) => <TableRows key={row.id} row={row} />)}
</>
);
};
or add return
const TableDisplay = ({ rows }) => {
return (
<>
{rows.map((row) => {
return <TableRows key={row.id} row={row} />;
})}
</>
);
};

Related

react js state value always false

hello im trying to make a array that contain a objects and i want to map this array into two tables :thisis stricture of array:
0
:
{title: 'uml', agreement: false}
1
:
{title: 'react', agreement: false}
2
:
{title: 'laravel', agreement: false}
length
:
3
[[Prototype]]
:
Array(0)
and i have a checkbox that make agreement true or false .
but the problem is everytime the agreement is false.
i want to send objects to first table if is true and to seconde table if is false but everytime is send to first table with false agreement .
this is all of code:
some functions is just to show the values of states
import './App.css';
import { useRef, useState } from 'react';
function App() {
const [modules,setModules]=useState([])
const [agreement,setAgreement]=useState()
const [title,setTitle]=useState()
const checkbox=useRef()
function handlecheck(){
setAgreement(checkbox.current.checked)
}
function handlechange(event){
setTitle(event.target.value)
}
function ajouter(){
setModules([...modules,{title,agreement}])
}
function affich(){
return console.log(modules)
}
return (
<div className="App">
<section class="container cd-table-container">
<h2 class="cd-title">Insert Table Record:</h2>
<input onChange={(event)=>handlechange(event)} type="text" class="cd-search table-filter" data-table="order-table" placeholder="module name" />
<button className='ajouter' onClick={()=>ajouter()} >Ajouter</button>
<button className='ajouter' onClick={()=>affich()} >affich</button>
<input type={"checkbox"} ref={checkbox} onChange={(event)=>handlecheck(event)} />
<table class="cd-table table">
<thead>
<tr>
<th>modules regionaux</th>
</tr>
</thead>
<tbody>
{
modules.map((elm,index)=>{
if(elm.agreement=true){
return (<tr>
<td>{elm.title}</td>
</tr>)
}
})
}
</tbody>
</table>
<br></br>
<table class="cd-table table">
<thead>
<tr>
<th>modules non regionaux</th>
</tr>
</thead>
<tbody>
{
modules.map((elm,index)=>{
if(elm.agreement=false){
return (<tr>
<td>{elm.title}</td>
</tr>)
}
})
}
</tbody>
</table>
</section>
</div>
);
}
export default App;
so first you don't have to use (useRef) hock just use (useState) will be better , second you were using the if statement with the assign operator sign you should use the double equal sign or the triple sign this the full code
import './App.css';
import { useRef, useState } from 'react';
function App() {
const [modules, setModules] = useState([])
const [agreement, setAgreement] = useState()
const [title, setTitle] = useState()
function handlecheck(e) {
setAgreement(e)
}
function handlechange(event) {
setTitle(event.target.value)
}
function ajouter() {
setModules([...modules, { title, agreement }])
}
function affich() {
return console.log(modules)
}
return (
<div className="App">
<section class="container cd-table-container">
<h2 class="cd-title">Insert Table Record:</h2>
<input onChange={(event) => handlechange(event)} type="text" class="cd-search table-filter" data-table="order-table" placeholder="module name" />
<button className='ajouter' onClick={() => ajouter()} >Ajouter</button>
<button className='ajouter' onClick={() => affich()} >affich</button>
<input type={"checkbox"} onChange={(event) => handlecheck(event.target.checked)} />
<table class="cd-table table">
<thead>
<tr>
<th>modules regionaux</th>
</tr>
</thead>
<tbody>
{
modules.map((elm, index) => {
if (elm.agreement === true) {
return (<tr>
<td>{elm.title}</td>
</tr>)
}
})
}
</tbody>
</table>
<br></br>
<table class="cd-table table">
<thead>
<tr>
<th>modules non regionaux</th>
</tr>
</thead>
<tbody>
{
modules.map((elm, index) => {
if (elm.agreement === false) {
return (<tr>
<td>{elm.title}</td>
</tr>)
}
})
}
</tbody>
</table>
</section>
</div>
);
}
export default App;

Is it possible to dipatsch on useSelector function?

Langage used : JS with REACT REDUX
The context : I have a component who render a list of quotes following the user filter and categories choice.
In my filter component, i store the select value (buttonsData), and here i re render a certains component depending on select value.
import React from 'react';
import { Table } from 'react-bootstrap';
import { useSelector } from 'react-redux';
//here each component following the user choice
import { AllForms } from './categories/AllForms';
import { AtoZ } from './sorted/AtoZ';
import { ZtoA } from './sorted/ZtoA';
import { Ascend } from './sorted/Ascend';
import CurrentOffers from './categories/CurrentOffers';
import ValidateOffers from './categories/ValidateOffers';
export const OfferList = () => {
const buttonsData = useSelector((state) => state.buttonReducer);
return (
<Table hover responsive="md" className="folder__table">
<thead className="folder__content">
<tr className="folder__titles">
<th className="folder__title"> </th>
<th className="folder__title">Order REF</th>
<th
className="folder__title"
>
Entité
</th>
<th className="folder__title">Customer</th>
<th className="folder__title">Status</th>
<th className="folder__title">Date</th>
<th className="folder__title "> </th>
</tr>
</thead>
{buttonsData.activeComponent === 'AllForms' && <AllForms />}
{buttonsData.activeComponent === 'Ascend' && <Ascend />}
{buttonsData.activeComponent === 'validate' && <ValidateOffers />}
</Table>
);
};
I have used createSelector to filter and sort my datas (working fine).
import { useSelector } from 'react-redux';
export const SelectOffersValidate = () => {
//here i select ALL my forms, get with axios
const formsDatas = useSelector((state) => state.offersReducer);
const sortedForms = [...formsDatas].filter(
(oneOffer) => oneOffer.status == 'validate'
);
console.log(sortedForms);
return sortedForms;
};
export const SelectOffersAscend = () => {
const formsDatas = useSelector((state) => state.offersReducer);
const sortedForms = [...formsDatas].sort((a, b) =>
b.createdAt.localeCompare(a.createdAt)
);
return sortedForms;
};
Here a component filtered ( i have one component for AllForms, one for Validate and one for ascend, exaclty the same but with own select function)
import React, { useState } from 'react';
import { FiEdit3 } from 'react-icons/fi';
import {
SelectOffersAscend,
} from '../../../selector/projects.selector.js';
import { isEmpty } from '../../../middlewares/verification.js';
import Moment from 'react-moment';
export const Ascend = () => {
const formsAscend = SelectOffersAscend();
return (
<>
<tbody>
{!isEmpty(formsAscend[0]) &&
formsAscend?.map((oneForm) => {
return (
<tr key={oneForm.id}>
<td>
<input
type="checkbox"
/>
</td>
<td>{oneForm.ref} </td>
<td> {oneForm.entity}</td>
<td>{oneForm.customer} </td>
<td>{oneForm.status} </td>
<td>
<Moment format="DD/MM/YYYY" date={oneForm.createdAt} />
</td>
<td>
<FiEdit3 />
</td>
</tr>
);
})}
</tbody>
</>
);
};
My first problem :
I have made a component for EACH filter, but it's repetitive, is there a better way to do ?
The second problem :
"AllForms" and "ValidateOffers" are categories and "Ascend" is a filter.
For the moment i filter only with AllForms but i would like to filtered based on categories choosen.
I've tried to create an action to store the actual categories, so i've tried to dispatch on my createSelector validate function but it's looping so i don't think is the best way to do
SOLUTION : thanks to Chris whol helped me :)
So i have delete all my filtered component to just have one and create a custom hook
import React, { useMemo } from 'react';
import { Table } from 'react-bootstrap';
import { useSelector } from 'react-redux';
import { OfferRows } from './OfferRows';
export const useFilteredOffers = () => {
const buttonsData = useSelector((state) => state.buttonReducer);
const offersData = useSelector((state) => state.offersReducer);
return useMemo(() => {
switch (buttonsData.activeComponent) {
case 'Ascend': // fix casing
return offersData?.sort((a, b) =>
b.createdAt.localeCompare(a.createdAt)
);
case 'validate':
return offersData?.filter((oneOffer) => oneOffer.status === 'validate');
case 'not validate':
return offersData?.filter(
(oneOffer) => oneOffer.status === 'not validate'
);
case 'AtoZ':
return offersData?.sort((a, b) => a.customer.localeCompare(b.customer));
case 'ZtoA':
return offersData?.sort((a, b) => b.customer.localeCompare(a.customer));
default:
return offersData;
}
}, [buttonsData.activeComponent, offersData]);
};
export const OfferList = () => {
const filteredOffers = useFilteredOffers();
return (
<Table hover responsive="md" className="folder__table">
<thead className="folder__content">
<tr className="folder__titles">
<th className="folder__title"> </th>
<th className="folder__title">Order REF</th>
<th className="folder__title">Entité</th>
<th className="folder__title">Customer</th>
<th className="folder__title">Status</th>
<th className="folder__title">Date</th>
<th className="folder__title "> </th>
</tr>
</thead>
<OfferRows offers={filteredOffers} />
</Table>
);
};
Here the rows
import React from 'react';
import { FiEdit3 } from 'react-icons/fi';
import Moment from 'react-moment';
import { isEmpty } from '../../middlewares/verification.js';
export const OfferRows = ({ offers }) => {
return (
<>
<tbody>
{!isEmpty(offers[0]) &&
offers?.map((oneForm) => {
return (
<tr key={oneForm.id}>
<td>
<input type="checkbox" />
</td>
<td>{oneForm.ref} </td>
<td> {oneForm.entity}</td>
<td>{oneForm.customer} </td>
<td>{oneForm.status} </td>
<td>
<Moment format="DD/MM/YYYY" date={oneForm.createdAt} />
</td>
<td>
<FiEdit3 />
</td>
</tr>
);
})}
</tbody>
</>
);
};
I would create a single component for the rendering of the offer rows. The data can be filtered using a single hook that also selects the active filter. You can also pass this down as an argument.
Custom hooks MUST start with the use keyword. See the Rules of Hooks documentation for more information.
const useFilteredOffers = () => {
const activeFilter = useSelector((state) => state.buttonReducer);
const offers = useSelector((state) => state.offersReducer);
return useMemo(() => {
switch (activeFilter) {
case 'Ascend': // fix casing
return offers?.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
case 'validate':
return offers?.filter(oneOffer => oneOffer.status == 'validate');
default:
return offers;
}
}, [activeFilter, offers]);
}
export const OfferList = () => {
const filteredOffers = useFilteredOffers();
return (
<Table hover responsive="md" className="folder__table">
<thead className="folder__content">
<tr className="folder__titles">
<th className="folder__title"> </th>
<th className="folder__title">Order REF</th>
<th
className="folder__title"
>
Entité
</th>
<th className="folder__title">Customer</th>
<th className="folder__title">Status</th>
<th className="folder__title">Date</th>
<th className="folder__title "> </th>
</tr>
</thead>
<OfferRows offers={filteredOffers} />
</Table>
);
};
For completeness, here is the OfferRows component.
PS: You won't need to use the isEmpty validator because Array#map won't have any effect when the Array is empty.
export const OfferRows = (offers) => {
return (
<>
<tbody>
{offers?.map((oneForm) => {
return (
<tr key={oneForm.id}>
<td>
<input
type="checkbox"
/>
</td>
<td>{oneForm.ref} </td>
<td> {oneForm.entity}</td>
<td>{oneForm.customer} </td>
<td>{oneForm.status} </td>
<td>
<Moment format="DD/MM/YYYY" date={oneForm.createdAt} />
</td>
<td>
<FiEdit3 />
</td>
</tr>
);
})}
</tbody>
</>
);
};

How to delete item seleted in table product

I am trying to delete a product, but it's doesn't show success. I do not know how to get the id of that product to delete
My button onClick = {handleDelete} is import from component in other folder. I try to create handleDelete function, but I missing something in this case.
This is my code for that section
import React, { useState, useEffect } from "react";
import { Container, Row, Col, Table } from "react-bootstrap";
import Loading from "../../components/Loading";
import Button from "../../components/Button/index"
import firebaseApp from "../../api/config";
const ProductTableList = ({
products,
loading,
fetchProductRequest
}) => {
useEffect(() => {
fetchProductRequest();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const firebaseDb = firebaseApp.database();
const [currentId, setCurrentId] = useState("");
if (loading) {
return (
<Container>
<Row>
<Col>
<Loading />
</Col>
</Row>
</Container>
);
}
const handleDelete = (id) => {
const productId = firebaseDb.ref().push().key;
if (window.confirm("Are you sure to delete this record?")) {
firebaseDb
.ref("products")
.child(`products/${productId}`)
.remove((err) => {
if (err) console.log(err);
else setCurrentId("");
});
}
}
const handleUpdate = (event) => {
//TODO
}
return (
<Table striped bordered hover className="product-table">
<thead>
<tr>
<th>No.</th>
<th className="image">Image</th>
<th>Name</th>
<th>Category</th>
<th>Price</th>
<th>Description</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{!!products && products.length > 0 ? (
products.map((product, index) => {
return (
<tr key={index}>
<td>{index}</td>
<td>{product.image}</td>
<td>{product.name}</td>
<td>{product.category}</td>
<td>{product.price}</td>
<td>{product.description}</td>
<td>
<Button onClick={handleDelete} btnText="Delete" />
<Button onClick={handleUpdate} btnText="Update" />
</td>
</tr>
);
})
) :
(
<tr><td className="center-title">Product list is empty!</td></tr>
)}
</tbody>
</Table>
)
}
export default ProductTableList;
Can anyone help me? How do I delete the product that I have selected
Can anyone explain or support for me why? Thank you so much
I made a example, you need to add your function on button click and use your item id to be removed.
import React, { useState, useEffect } from "react";
import { Table } from "react-bootstrap";
const ProductTableList = () => {
const [currentId, setCurrentId] = useState("");
const [products, setProducts] = useState([{
image: 'image',
name: '01',
category: '01',
price: '01',
description: '01'
},
{
image: 'image',
name: '02',
category: '02',
price: '02',
description: '02'
},
{
image: 'image',
name: '03',
category: '03',
price: '03',
description: '03'
}])
const handleDelete = (id) => {
const removeItem = products.filter((item) => item !== products[id])
setProducts(removeItem)
}
return (
<Table striped bordered hover className="product-table">
<thead>
<tr>
<th>No.</th>
<th className="image">Image</th>
<th>Name</th>
<th>Category</th>
<th>Price</th>
<th>Description</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{!!products && products.length > 0 ? (
products.map((product, index) => {
return (
<tr key={index}>
<td>{index}</td>
<td>{product.image}</td>
<td>{product.name}</td>
<td>{product.category}</td>
<td>{product.price}</td>
<td>{product.description}</td>
<td>
<button onClick={() => handleDelete(index)}>Delete</button>
</td>
</tr>
);
})
) :
(
<tr><td className="center-title">Product list is empty!</td></tr>
)}
</tbody>
</Table>
)
}
export default ProductTableList;
Also, avoid index as element key
{ items.map((item, index) => (<li key={index}>{item}</li>)) }
When a list item was added or removed, and the key kept the same, the React assumed that the DOM element had not changed, and the app could not render.
An alternative to cases that the list doesn't have a unique ID is to generate one using shortID.
https://www.npmjs.com/package/shortid

How do I get the <td> values in a row onClick

import React from 'react';
import { Table } from 'reactstrap';
import './SearchDataTable.css'
const SearchDataTable = (props) => {
const serverData = props.serverData
const handleRowClick = (rowValue) => {
console.log(rowValue)
}
return(
<div>
<Table bordered>
<thead>
<tr>
<th>Affected</th>
<th>Type</th>
<th>Quantity</th>
</tr>
</thead>
<tbody>
{props.sortData ? (serverData.sort((a,b) => a.quantity - b.quantity).map(data => (
<tr className="table-row" onClick={(e) => handleRowClick(e)} key={data.quantity}>
<td>{data.affectedOn}</td>
<td>{data.type}</td>
<td>{data.quantity}</td>
</tr>
))):(serverData.sort((a,b) => b.quantity - a.quantity).map(data => (
<tr key={data.quantity}>
<td>{data.affectedOn}</td>
<td>{data.type}</td>
<td>{data.quantity}</td>
</tr>
))) }
</tbody>
</Table>
</div>
)
}
export default SearchDataTable;
From the above code I tried getting the corresponding <td> value onClicking the row. I added the onClick on <tr> and tried, but failed in doing it. I need some help in solving this.
Instead of passing e to handleRowClick, pass the data.
import React from 'react';
import { Table } from 'reactstrap';
import './SearchDataTable.css'
const SearchDataTable = (props) => {
const serverData = props.serverData
const handleRowClick = (rowValue) => {
console.log(rowValue)
}
return(
<div>
<Table bordered>
<thead>
<tr>
<th>Affected</th>
<th>Type</th>
<th>Quantity</th>
</tr>
</thead>
<tbody>
{props.sortData ? (serverData.sort((a,b) => a.quantity - b.quantity).map((data, index) => (
<tr className="table-row" onClick={() => handleRowClick(data)} key={index}>
<td>{data.affectedOn}</td>
<td>{data.type}</td>
<td>{data.quantity}</td>
</tr>
))):(serverData.sort((a,b) => b.quantity - a.quantity).map((data, index) => (
<tr key={index}>
<td>{data.affectedOn}</td>
<td>{data.type}</td>
<td>{data.quantity}</td>
</tr>
))) }
</tbody>
</Table>
</div>
)
}
export default SearchDataTable;
Also replaced the key on the rows with index instead of quanity, since it seems like quantity would not be a unique identifier. Ideally, you would have something else that is unique, like an id property, but index can be okay if not.
const handleRowClick = (data) => {
console.log(data.affectedOn, data.type, data.quantity)
}
....
<tr onClick={() => this.handleClick(data)}>
<td>{data.affectedOn}</td>
<td>{data.type}</td>
<td>{data.quantity}</td>
</tr>
....

Open Modal from Table Row in React

openBookDetails sets isBookDetailsOpen: true which should change the className in showHideClassName to modal display-block and it should show on the screen but the modal doesn't show. However it appears in Elements in the Development tools
import React, { Component } from 'react';
import './Update.css';
import Search from '../Search/Search';
// import Modal from './Modal/Modal';
const Table = ({ data, openBookDetails }) => (
<table class="table table-hover">
<thead>
<tr class="table-primary">
<th scope="col">Title</th>
<th scope="col">Author</th>
<th scope="col">ISBN</th>
<th scope="col">No. Of Copies</th>
</tr>
</thead>
<tbody>
{data.map(row =>
<TableRow key={row.id} row={row} openBookDetails={openBookDetails}/>
)}
</tbody>
</table>
)
const TableRow = ({ row, openBookDetails }) => (
<tr class="table-light" onClick={openBookDetails}>
<th scope="row" >{row.title}</th>
<td >{row.author}</td>
<td >{row.isbn}</td>
<td >24</td>
</tr>
)
const Modal = ({ closeBookDetails, isBookDetailsOpen, children }) => {
const showHideClassName = isBookDetailsOpen ? 'modal display-block' : 'modal display-none';
return (
<div className={showHideClassName}>
<section className='modal-main'>
{children}
<button
onClick={closeBookDetails}
>
Close
</button>
</section>
</div>
);
};
class Update extends Component{
constructor(props) {
super(props);
this.state = {
value: '',
suggestions: [],
setOfAllBooks: [],
searchedBooks: [],
isBookDetailsOpen: false,
};
this.openBookDetails = this.openBookDetails.bind(this);
this.setTableData = this.setTableData.bind(this);
}
setTableData(searchedBook){
this.setState({searchedBooks: searchedBook})
console.log(this.state.searchedBooks)
}
openBookDetails(){
console.log('openBookDetails')
this.setState({ isBookDetailsOpen: true})
}
closeBookDetails(){
this.setState({ isBookDetailsOpen: false})
}
render(){
return(
<main>
<div class="container">
<Search state={this.state} setTableData={this.setTableData} />
<Table data={this.state.searchedBooks} openBookDetails={this.openBookDetails}/>
<Modal isBookDetailsOpen={this.state.isBookDetailsOpen} closeBookDetails={this.closeBookDetails} />
{/* <Modal /> */}
</div>
</main>
)
}
}
export default Update;

Resources