Total noob here,
I was adapting the following tutorial (' https://www.youtube.com/watch?v=hson9BXU9F8&t=925s&ab_channel=Codevolution ') for my personal project, however my table does not show any data, I have tried comparing my project to the reference and even copying directly but i don't get any errors so its very difficult to pinpoint where I messed up.
TABLE COMPONENT
import React, { useMemo } from 'react'
import { useTable } from 'react-table'
import MOCK_DATA from './MOCK_DATA.json'
import { COLUMNS } from './columns'
import './table.css'
export const BasicTable = () => {
const columns = useMemo(() => COLUMNS, [])
const data = useMemo(() => MOCK_DATA, [])
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow
} = useTable({
columns,
data
})
return (
<>
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()}>{column.render('Header')}</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map(row => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
})}
</tr>
)
})}
</tbody>
</table>
</>
)
}
COLUMNS COMPONENT
export const COLUMNS = [
{
//nombra la columna, se le puede poner cualquie nombre
Header : 'id',
//determina el elemento del JSON a acceder
accesor: "id",
disableFilters: true,
sticky: 'left'
},
{
Header : 'nombre_usuario',
accesor: 'nombre_usuario'
},
{
Header : 'correo_usuario',
accesor: 'correo_usuario'
},
{
Header : 'Rol_usuario',
accesor: 'rol_usuario'
},
{
Header : 'Estado_usuario',
accesor: 'estado_usuario'
},
{
Header : 'ident_usuario',
accesor: 'id'
},
]```
MOCK JSON EXAMPLE
[{"id":1,"nombre_usuario":"Skipton Noquet","pw_usuario":"r7ND2xcYb","correo_usuario":"snoquet0#naver.com","rol_usuario":"adipiscing","estado_usuario":"phasellus","ident_usuario":"937"}]
here is the repo from the tutorial i have been following, it works perfectly (it has an older version of react table, I tried it out and it didn't work either):
https://github.com/gopinav/React-Table-Tutorials.git
Use page instead of rows
{page.map(row => {...}
Related
So I have a user drop down menu that allows a person to impersonate a user to get a list of buckets. If you pick a different user it then makes an api call to then get a new list of buckets based upon that user. I am using react-table to create a table with information about the user's buckets. I can change the user on the other pages and the user gets updated and nothing explodes. But if I do it on the bucket page, it returns this:
The API call which happens in the parent component of my bucketTable component in the useEffect hook and that is tied to the user that I drop down from the app.js. The API call fires off and returns a list of buckets which I then pass down to my bucketTable component which then takes it and inserts it into a react-table.
I have an onChange event that bubbles up to App.js from my navbar and then drop the selected user down to the buckets page. Which then does an API call using useEffect which is then tied to the user field that I am passing around.
bucketTable.js
so the issue is that when I change the userDropdown on the navbar which then updates that value in the buckets.js component to get the list of buckets, this table page gets overwhelmed. I don't understand why I see my use effect is firing only when user is fired. I have done console.log statements and see that it only gets fired when I change it once, but this happens. This makes me think that something is rerendering over and over again causing this issue. Please help been pulling my hair out on this and I can provide more details upon request.
EDIT:
So when I change the user ON the bucket page which renders the bucketTable component I see that the bucket Table component is being rerendered a billions times...still looking into this will update when I have more information.
this is my bucketTable.js which is being rendered a TON when I change the user.
import "../index.css";
import { useTable } from "react-table";
const BucketTable = ({ buckets }) => {
console.log('BucketTable Rendered')
const data = []
const columns = [
{
Header: "Bucket Name",
accessor: "bucket",
},
{
Header: "Created By",
accessor: "created_by",
},
{
Header: "Storage Label",
accessor: "storage_label",
},
{
Header: "Zone",
accessor: "zone",
}
];
// Must only get the array cleansing of objs
buckets.buckets.forEach((x) => data.push(x));
console.log(data)
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } =
useTable({
columns,
data
});
return (
<>
<table {...getTableProps()}>
<thead>
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
<th {...column.getHeaderProps()}>{column.value}</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell) => {
return (
<td {...cell.getCellProps()}>{cell.value}</td>
);
})}
</tr>
);
})}
</tbody>
</table>
</>
);
};
export default BucketTable;
buckets.js which calls the bucketTable.js component
import { useEffect, useState } from "react";
import BucketList from "../Components/BucketList";
import useCollapse from "react-collapsed";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import * as AiIcons from "react-icons/ai";
import BucketTable from "../Components/BucketTable";
// TODO: Shift from cards to table
const Buckets = ({ user }) => {
const [bucketList, getBuckets] = useState(null);
const { getCollapseProps, getToggleProps, isExpanded } = useCollapse();
const [selectedACL, setValue] = useState("private");
const callGetBuckets = () => {
console.log("callGetBuckets Called")
const headers = {
"Content-Type": "application/json",
user: user,
};
notify("loading");
fetch("http://localhost:5000/rest/v1/buckets", { headers })
.then((res) => {
return res.json();
})
.then((data) => {
console.log('fired off?')
getBuckets(data);
notify("dismiss");
});
};
useEffect(() => {
console.log("useEffect fired")
callGetBuckets();
}, [user]);
const notify = (type) => {
switch (type) {
case "success":
toast.success("Bucket Created", {
toastId: "Success",
});
break;
case "fail":
toast.error("Bucket Creation Failed", {
toastId: "fail",
});
break;
case "loading":
toast.loading("Loading...", {
toastId: "loading",
});
break;
case "dismiss":
toast.dismiss();
break;
default:
}
};
const handleSubmission = (e) => {
e.preventDefault();
const requestOptions = {
method: "POST",
headers: { "Content-Type": "application/json", user: user },
body: JSON.stringify({
bucket: e.target.Name.value,
storage_label: e.target.StorageLabel.value,
acl: selectedACL,
}),
};
fetch("http://localhost:5000/rest/v1/bucket/create", requestOptions).then(
(res) => {
if (res.ok) {
notify("success");
console.log('fired off as well')
callGetBuckets();
} else notify("fail");
}
);
};
return (
<div>
<ToastContainer theme="theme" />
<div className="content">
<h2 className="bucketHeader">Buckets</h2>
<div>
<p>Returns a list of buckets that a user has access to view.</p>
</div>
<div className="collapsible">
<div className="header" {...getToggleProps()}>
Create Bucket
<span>
{isExpanded ? (
<AiIcons.AiOutlineArrowUp />
) : (
<AiIcons.AiOutlineArrowDown />
)}
</span>
</div>
<div {...getCollapseProps()}>
<div className="content-collapsible">
<form className="createBucketForm" onSubmit={handleSubmission}>
<label className="collapsible-label">
Name:
<input type="text" name="Name" />
</label>
<label className="collapsible-label">
Storage Label:
<input type="text" name="StorageLabel" />
</label>
<div className="dropDownForm">
<label className="collapsible-label">
ACL:
<span className="dropdown">
<label className="dropLabel">
<select
value={selectedACL}
onChange={(e) => setValue(e.target.value)}
>
<option value="private">private</option>
<option value="public-read">public-read</option>
<option value="public-read-write">
public-read-write
</option>
<option value="authenticated-read">
authenticated-read
</option>
</select>
</label>
</span>
</label>
</div>
<div>
<input className="formSubmit" type="submit" value="Submit" />
</div>
</form>
</div>
</div>
</div>
{bucketList && <BucketTable buckets={bucketList} />}
</div>
</div>
);
};
export default Buckets;
The answer for this was to move the const columns out of the component file. I moved it into its own file and imported it to the parent component then dropped it down as a prop and everything worked fine from there. THe reasoning I am still baffled as to why that happened. I still had issues when I imported it directly to the table component but when I brought the columns in as a prop it fixed itself. But that was the fix for the infinite rendering.
const columns = [ { Header: "Bucket Name", accessor: "bucket", }, { Header: "Created By", accessor: "created_by", }, { Header: "Storage Label", accessor: "storage_label", }, { Header: "Zone", accessor: "zone", } ];
I'm mapping an array to have the Link which gonna direct me to modify one row of the table
This is my DepotList Component :
import React from 'react';
import { Link } from 'react-router-dom';
import Table from '../../../Common/Table';
import { textFilter } from 'react-bootstrap-table2-filter';
const DepotList = props => {
const { depots } = props;
const columns = [
{
dataField: 'name',
text: 'nom depot',
},
{
dataField: 'adress',
text: 'adresse',
sort: true,
},
{
dataField: 'size',
text: 'Taille depot',
},
{
dataField: 'equipements',
text: 'Equipements',
},
{
dataField: 'updated',
text: 'Mis à jour',
},
{
dataField: '',
text: 'Actions',
formatter: () => {
return (
<>
{depots.map((depot, index) => (
<div>
<Link
className=""
to={`/gestion-depots/edit/${depot._id}`}
key={index}
>
{console.log(`index ${depot._id}`)}
Modifier
</Link>
</div>
))}
</>
);
},
},
];
return (
<>
<p>{depots.length} Depots</p>
{console.log('depotlist ----', depots)}
<Table data={depots} columns={columns} csv search filter />
</>
);
};
export default DepotList;
But I'm getting n links in every action row like this :
And if i click the link it works perfectly lol : first link first row , second link second row ..etc
Can anyone help me to fix this problem !!
This is the Table Component
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import cellEditFactory, { Type } from "react-bootstrap-table2-editor";
import filterFactory, { textFilter } from "react-bootstrap-table2-filter";
import paginationFactory from "react-bootstrap-table2-paginator";
import ToolkitProvider, {
CSVExport,
Search
} from 'react-bootstrap-table2-toolkit';
const indication = () => {
return 'Oops! No data now! Please try again!';
};
const { ExportCSVButton } = CSVExport;
const { SearchBar } = Search;
const Table = props => {
const {
data,
columns,
striped,
hover,
condensed,
csv,
search,
clickAction,
isRowEvents,
filter,
cellEdit,
pagination
} = props;
const rowEvents = {
onClick: (e, row, rowIndex) => {
clickAction(row._id, rowIndex);
}
};
const selectRow = {
mode: "checkbox",
clickToSelect: true,
clickToEdit: true,
};
return (
<ToolkitProvider
keyField='_id'
data={data}
columns={columns}
exportCSV={csv}
search={search}
filter={filter}
cellEdit={cellEdit}
pagination={pagination}
>
{props => (
<div className='table-section'>
{csv && (
<div className='csv'>
<ExportCSVButton
className='input-btn custom-btn-secondary md'
{...props.csvProps}
>
Exporter CSV
</ExportCSVButton>
</div>
)}
{search && (
<div className='search'>
<SearchBar {...props.searchProps} />
</div>
)}
<BootstrapTable
{...props.baseProps}
keyField='_id'
data={data}
columns={columns}
striped={striped}
hover={hover}
condensed={condensed}
pagination={paginationFactory()}
cellEdit={cellEditFactory({
mode: "dbclick",
blurToSave: true,
nonEditableRows: () => [1, 2, 3],
})}
noDataIndication={indication}
rowEvents={isRowEvents ? rowEvents : null}
filter={filterFactory()}
/>
</div>
)}
</ToolkitProvider>
);
};
export default Table;
depots is probably an array and in the last index of your columns you are mapping it with "Modifier" as its inner text.
formatter: () => {
return (
<>
{depots.map((depot, index) => (
<div>
<Link
className=""
to={`/gestion-depots/edit/${depot._id}`}
key={index}
>
{console.log(`index ${depot._id}`)}
Modifier
</Link>
</div>
))}
</>
);
},
Can you also share the table component, and the depots array list.
You are mapping all your depots array in your formatter so in each row you got all the links
I'm not sure of the logic you implemented in your Table component but you probably can solve the problem changing your last element of columns in this way
{
dataField: '_id',
text: 'Actions',
formatter: (_id) => {
return (
<div>
<Link
className=""
to={`/gestion-depots/edit/${_id}`}
key={index}
>
{console.log(`index ${_id}`)}
Modifier
</Link>
</div>
);
},
},
all you have to change is the parameters that you are passing to formatter in your table component based on the datafield
or you can pass the whole item to formatter and do your extraction on the single item
export const COLUMNS = [
{
Header : 'Total Cases',
accessor : 'totalcases',
},
{
Header : 'Active Cases',
accessor : 'activecases',
},
{
Header : 'Total Recovery',
accessor : 'recovery',
},
{
Header : 'Total Death',
accessor : 'deaths',
},
{
Header : 'New Cases',
accessor : 'newcases',
},
]
function Table({countryData}) {
const columns = useMemo(()=> COLUMNS, []);
const data = useMemo(()=> countryData, []);
const {
....
setGlobalFilter,
} = useTable({
columns,
data
}, useGlobalFilter, useSortBy);
const{globalFilter} = state;
return (
<>
<GlobalFilter filter={globalFilter} setFilter={setGlobalFilter}/>
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps(column.getSortByToggleProps())}>{column.render('Header')}</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row, i) => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
})}
</tr>
)
})}
</tbody>
</table>
</>
)
}
export default Table
here I want to sort the entire table by default on the basis of new cases column and want toggle sort only on active cases and recovery. as Im new to react i dont know how to provide custom sort..............................................................................................................................................................................................................................................................
you can use :
columns.sort((a, b) => (a.accessor > b.accessor ) ? 1 : -1) More informision at this link: https://flaviocopes.com/how-to-sort-array-of-objects-by-property-javascript/
Hopefully this isn't too much of an overly basic question (though I think it might be). I've spent a few days trying to figure this out with no luck, I'm new at this.
I'm trying to use GraphQL with Shopify to generate a react-table with a bunch of information from the orders I receive on Shopify. I've gotten as far as being able to generate the data I want, but I can't seem to get it to generate a new row for each piece of data in the array.
As you can see from the image below, I just get '#1001', '#1002' in the same cell. Those are two different orders that I want on individual rows. I'm certain I need to use .map in a fashion and tell the react-table to push data, but nothing I've tried seems to work, and if it does it provides me with two individual rows- but no data in said rows.
I also think the way I'm telling the table to get the data is wrong. I need to use the accessors in my header section to define certain data that I receive from the query. Most of the accessors aren't correct barring orderNumber, Payment, customer. This is because I need to take information from lineItems and distribute it across multiple columns depending on the product. This question isn't really about this headache, but I just wanted to contextualise why some columns are missing accessors.
Here is my query:
import { gql } from '#apollo/client';
const wholesaleOrders = gql`
{
orders(first: 2, query: "tag:wholesale") {
edges {
node {
id
unpaid
fullyPaid
name
customer {
displayName
defaultAddress {
company
}
}
lineItems(first: 5) {
edges {
node {
quantity
name
}
}
}
}
}
}
}
`;
export default wholesaleOrders;
and here is my Table:
import React from 'react'
import styled from 'styled-components'
import { useTable } from 'react-table'
import { graphql, Query } from 'react-apollo';
import { gql, useQuery } from '#apollo/client';
import wholesaleOrders from './QueryData.js'
function Table({ columns, data }) {
// Use the state and functions returned from useTable to build your UI
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
} = useTable({
columns,
data,
});
// Render the UI for your table
return (
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()}>{column.render('Header')}</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row, i) => {
prepareRow(row)
return (
<tr {...row.getRowProps()} >
{row.cells.map(cell => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
})}
</tr>
)
})}
</tbody>
</table>
)
}
function DataTable() {
const columns = React.useMemo(
() => [
{
Header: 'Order',
columns: [
{
Header: 'Order',
accessor: 'orderNumber',
},
{
Header: 'Status',
accessor: 'payment'
},
{
Header: 'Customer',
accessor: 'customer'
},
],
},
{
Header: 'Wholesale 2kg',
columns: [
{
Header: 'EST',
accessor: 'lineItems'
},
{
Header: 'TB'
},
{
Header: 'BB'
},
{
Header: 'OTHER'
},
],
},
{
Header: 'Retail and Misc.',
columns: [
{
Header: '250g'
},
{
Header: 'Tea/Chocolate'
},
{
Header: 'Equipment'
},
{
Header: 'After Hours'
},
{
Header: 'Notes'
},
],
},
],
[]
)
return (
<Query
query={wholesaleOrders}>
{({ data, loading, error }) => {
if (loading) return <div>Loading…</div>;
if (error) return <div>{error.message}</div>;
console.log(data);
return (
<Table
data={[{orderNumber: data.orders.edges.map(({node}) => node.name )}]}
columns={columns}
defaultPageSize={10}
/>
);
}}
</Query>
)
}
export default DataTable;
and here is the result:
Result
Apologies for how verbose this is, I just wanted to cover all bases.
Thanks!
Nevermind, moron figured it out:
return (
<Query
query={wholesaleOrders}>
{({ data, loading, error }) => {
if (loading) return <div>Loading…</div>;
if (error) return <div>{error.message}</div>;
console.log(data);
return (
<Table
data={data.orders.edges.map((order) => {
return (
{
orderNumber: order.node.name,
payment: order.node.fullyPaid,
customer: order.node.customer.displayName,
});
})}
columns={columns}
defaultPageSize={10}
/>
);
}}
</Query>
)
}
Result
Days, days of trying to figure this out and I figure out after I post the question.
I'm doing a leaderboard for a game. The userInfo array that i am using contains fetched data from a json table. The array contains id, username, bestattempts and besttime along with the data from each category.
This table currently have 4 columns with and all the data from the json table is on table rows. I need to have the table not showing the "id" column, and instead showing a new "Rank" first column with a autoincrement row data [1,2,3,4,5] (Like on a leaderboard).
How can i make that happen with Object.keys working?
import React from "react";
import "./LeaderBoard.css";
const Head = ({keys, head}) => {
return (
<thead>
<tr>
{
keys.map(key =><th key={key}>{head[key] || key}</th> )
}
</tr>
</thead>
)
}
const Row = ({row}) => {
const keys = Object.keys(row)
return (
<tr key={row.id}>
{
keys.map(key => <td key={key}>{row[key]}</td>)
}
</tr> )
}
const LeaderBoard = ({usersInfo, head}) => {
const newArray = usersInfo.map(({ id, ...rest }, index) => ({ Rank: index + 1, ...rest }) )
newArray.sort(function sortByAttempts(a, b) {
return (a.bestattempts - b.bestattempts) && (a.besttime - b.besttime)
});
const keys = Object.keys(newArray[0])
return (
<div className="Leaderboard-wrapper">
<table>
<Head keys={keys} head={head}/>
<tbody>
{
newArray.map((row) => <Row row={row}/>)
}
</tbody>
</table></div>
)
};
export default LeaderBoard;