How to access data outside the function using axios and react js - reactjs

when call the retriveStudentPhoto() function from h1 tag . I can't get the value return .How do I solve this.
Thanks in advance .
{data.map((val, index) => (
<tr>
<td style={{ outline: 'none' }} data-heading="Photo">
<h1{ retriveStudentPhoto(val.email) }</h1> /*call
this function */
</td>
))}
function retriveStudentPhoto (email) {
var photo = ""
axios.get(`/user-info/${email}`)
.then((result)=>{
photo = result.data[0].profile_photo;
}).catch((error)=>error)
return photo ;
}
Since the function is inside the map , there will be call multiple times and the value will be returned each time. I used the useState hook but not getting results as per demand.
please help me more. Thanks in advance.
complete Code :
import React, { useEffect, useState } from 'react';
import { Button, Alert } from 'react-bootstrap';
import $ from 'jquery';
import axios from '../../config/axios';
import '../Attendance_Table/css/App.scss';
import { useAuth } from "../../contexts/AuthContext";
import { Link, useHistory } from 'react-router-dom';
function PeopleList({ match }) {
const course_code = match.params.course_code;
const { currentUser } = useAuth();
const history = useHistory();
const [msg, setMsg] = useState("");
const [course_name, setcourse_name] = useState("");
var breakOn = 'medium'
let tableClass = 'table-container__table';
if (breakOn === 'small') {
tableClass += ' table-container__table--break-sm';
} else if (breakOn === 'medium') {
tableClass += ' table-container__table--break-md';
} else if (breakOn === 'large') {
tableClass += ' table-container__table--break-lg';
}
const headingColumns = ['Photo', 'Student ID', 'Name', 'Email']
const headingColumns2 = ['Photo', 'Name', 'Email']
const [data, setData] = useState([]);
const [studentsPhoto, setStudentsPhoto] = useState([]);
const [techInfo, setTechInfo] = useState([]);
useEffect(() => {
axios.get(`/course/info/${course_code}`).then((result) => {
setcourse_name(result.data[0].course_name)
})
SearchHandle();
}, [])
let SearchHandle = () => {
axios.get(`people/${course_code}`).then((result) => {
setData(result.data)
// teacher info retrieve
axios.get(`user-info/${result.data[0].tecEmail}`)
.then((res) => {
setTechInfo(res.data[0]);
})
//close teacher retrieve
let student_photo = [];
let promises = [];
for (let i = 0; i < result.data.length; i++) {
promises.push(
axios.get(`/user-info/${result.data[i].email}`)
.then((res) => {
student_photo.push(res?.data[0]?.profile_photo)
})
)
}
Promise.all(promises).then(() => {
setStudentsPhoto(student_photo);
})
}).catch((err) => console.log(err))
}
function retriveStudentPhoto(email) {
var photo = "";
axios.get(`/user-info/${email}`)
.then((result) => {
var photo = result.data[0].profile_photo;
}).catch((error) => error)
return photo;
}
return (
<div>
{/* {msg ? ( */}
<div>
<div className="table-container" style={{ backgroundColor: 'white' }}>
<div className="table-container__title">
<h5>People -- {course_name}({course_code})</h5>
</div>
<h5 style={{ padding: '10px', fontFamily: 'roboto' }}>Teacher</h5>
<table style={{ outline: 'none', border: 'none' }} className={tableClass}>
<thead>
<tr>
{headingColumns2.map((col, index) => (
<th data-heading={index} key={index}>{col}</th>
))}
</tr>
</thead>
<tbody>
<tr>
<td style={{ outline: 'none' }} data-heading="Photo">
{techInfo.profile_photo ? (
<img style={{ borderRadius: '150px', height: '40px', width: '40px' }}
src={techInfo.profile_photo} />
) : (
<img style={{ borderRadius: '150px', height: '40px', width: '40px' }}
src="https://lh3.googleusercontent.com/-XdUIqdMkCWA/AAAAAAAAAAI/AAAAAAAAAAA/4252rscbv5M/s75-c-fbw=1/photo.jpg" />
)}
</td>
<td data-heading="Student Name">{techInfo.name} </td>
<td data-heading="Student Email"><span style={{ fontSize: '11.5px' }}>{techInfo.email}</span> </td>
</tr>
</tbody>
</table><br />
<br />
{data.length ? (
<table style={{ outline: 'none', border: 'none' }} className={tableClass}>
<thead>
<tr>
{headingColumns.map((col, index) => (
<th data-heading={index} key={index}>{col}</th>
))}
</tr>
</thead>
<tbody>
{data.map((val, index) => (
<tr>
<td style={{ outline: 'none' }} data-heading="Photo">
<h1>{retriveStudentPhoto(val.email)}</h1>
</td>
<td style={{ outline: 'none' }} data-heading="Student ID">{val.student_id}</td>
<td data-heading="Student Name">{val.student_name} </td>
<td data-heading="Student Email"><span style={{ fontSize: '11.5px' }}>{val.email}</span> </td>
</tr>
))}
</tbody>
</table>
) : (
<div>
<Alert className="md-4 w-100" variant="danger">
No Student add to this course yet
</Alert>
</div>
)}
<br />
<div style={{ textAlign: 'center', paddingBottom: '5px' }}>
<Link to={`/attendance-sheet/${course_code}`}><span>Back to {course_code}</span></Link>
</div>
</div>
</div>
{/* ) : ""} */}
</div>
);
}
export default PeopleList;

Render is a pure, synchronous function. If you need to make asynchronous calls then do this in a lifecycle, in this case, a useEffect hook and store the results in state to be rendered.
Iterate over the result.data array and issue the GET request, and when the request resolves issue a functional state update to create a new data array, using the iterated element's index to inject a new photo property.
const SearchHandle = () => {
axios.get(`people/${course_code}`)
.then((result) => {
setData(result.data);
result.data.forEach(async (item, index) => {
try {
const result = await axios.get(`/user-info/${item.email}`);
const photo = result.data[0].profile_photo;
setData(data => data.map(
(el, i) => i === index
? { ...el, photo }
: el)
)
} catch(error) {
// log error, etc...
}
});
...
}
In the render access the new photo property you added above.
{data.map((val, index) => (
<tr key={val.student_name}>
<td style={{ outline: 'none' }} data-heading="Photo">
<h1>{val.photo}</h1>
</td>
<td style={{ outline: 'none' }} data-heading="Student ID">{val.student_id}</td>
<td data-heading="Student Name">{val.student_name} </td>
<td data-heading="Student Email">
<span style={{ fontSize: '11.5px' }}>{val.email}</span>
</td>
</tr>
)
)}

You are trying to use a function with async data in the render, so probably you dont have the data yet.
Try to keep the data from that axios.get in the state, youd probably want also to implement useEffect to make the call and store it to the state when component mounts

Related

cannot seem to get table header to display

I have a table where I am feeding data into it from an api, the data is fetched correctly and displays properly for the table row and data which is part of the tbody but inside the thead I try to display a header but nothing seems to be displayed even though the data being passed to the header is being logged to the console. Can anyone see my issue?
Component with table:
import React, {useState, useEffect} from 'react';
import secondsToMinutes from '../utils/utils';
function Table(props) {
const styles = {
div: {
width: 'auto',
height: 'auto',
margin: '0 auto',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
},
};
const [table, setTable] = useState();
useEffect(() => {
setTable(<table >
<thead>
<tr>
{props.headerData.map(header => {
console.log("table header = ", header);
{header.map((item, i) => {
console.log("header item", item.name)
return (<th
} key={i}>{item.name}</th>
)})}
})}
</tr>
</thead>
<tbody>
{props.data.map((array, index) => (
<tr key={index}>
{array.map((item, i) => {
return (
<tr>
<td key={i}>{item.nameValue} </td>
</tr>
)
})}
</tr>
))}
</tbody>
</table>)
}, [props.data, props.header]);
return (
<div style={styles.div}>
{table}
</div>
)
}
export default Table;
You're not returning anything from the outer map().
Change the thead to:
<thead>
<tr>
{
props.headerData.map(header => {
console.log("table header = ", header);
return header.map((item, i) => {
console.log("header item", item.name)
return (<th key={i}>{item.name}</th>)
})
}}
}
</tr>
</thead>
Note the return before header.map
That said, you shouldn't save the DOM element to the useState. Rather save the data to the state, and then in your return render function render the table

how to show focus in first row React js?

Code:-
const myRef = React.createRef([]);
const handleKeyDown = (event, ID) => {
//up and Down key
const active = document.activeElement;
active.addEventListener('keydown', function (event) {
switch (event.key) {
case "ArrowUp":
active?.previousElementSibling?.focus();
event.preventDefault();
break;
case "ArrowDown":
active?.nextElementSibling?.focus();
event.preventDefault();
break;
default: break;
}
});
}
const active = () => {
myRef.current.focus()
}
return (
<div className="mainContent">
<div className="tableHeaderBody">
<div className="TableText">PlayList</div> <div className="ClossIcon"><FaCircle style={{ color: "#FC0000", width: "10px", height: "10px", alignItems: "right" }} /></div>
</div>
<div className="tableBody" >
<table className="table">
<Header
headers={headers}
/>
<tbody>
{comments.map((comment) => {
//Display Hex to base64 image format
const base64 = Buffer.from(comment.Thumbnail, 'hex').toString('base64');
//console.log(base64);
const statusContent = () => {
if (comment.Status === 0) {
return <div><BsFillCircleFill style={{ color: "#FF0000", width: "20px" }} /> Not Ready</div>;
} else if (comment.Status === 1) {
return <div><BsFillCircleFill style={{ color: "#41fc00", width: "20px" }} /> Ready</div>;
} else if (comment.Status === 2) {
return <button type="Submit" style={{ backgroundColor: "blue" }}>Cueing</button>;
} else if (comment.Status === 3) {
return <button type="Submit" style={{ backgroundColor: "yellow", color: "Black" }}>Cued</button>;;
} else {
return <button type="Submit">Playing</button>;
}
};
return (
<tr key={comment.idx} tabIndex={comment.idx} className="border_bottom" onKeyDown={(e) => handleKeyDown(e, comment.idx)} onLoad={() => active()} ref={myRef}>
<td style={{ color: "white", width: "200px" }}>
<img src={`data:image/jpeg;base64,${base64}`} alt="Clip Thumbnail" width="100%" />
</td>
<td style={{ color: "white", width: "440px" }}>{comment.ClipName}</td>
i using myRef.current.focus() in active = () but it's show me focus in last row when i load the page
i want that when page load focus show in first row and user use up and down key in table row without clicking the table row
enter image description here
As i load the page focus automatically placed in last row show in image how to fix that? please help
What I think is happening, is that onLoad triggers for every rendered row. So when the last row is rendered it is the last time onLoad triggers and focuses on this row. To overcome this issue:
const active = (rowNumber) => {
if (rowNumber === 0) {
myRef.current.focus()
}
}
And in the tag in the onLoad pass it as:
<tr key={comment.idx} tabIndex={comment.idx} className="border_bottom" onKeyDown={(e) => handleKeyDown(e, comment.idx)} onLoad={() => active(comment.idx)} ref={comment.idx === 0 && myRef}>
You are giving all rendered row the same ref, that might cause an issue too so I conditioned it to give the ref only to the first row.

Why my props are undefined when sending to components?

I have a table in my project and I have an edit / view / add page that I can access from this table. My goal is to send the clicked data to the other component without any problem, but no matter how hard I try, I get an undefined error and the project is broken. I would be glad if you could help.
I am sharing my codes from parent to child component
Table page.
import React, { useState, useEffect, useCallback, useMemo } from "react";
import ManagementTable from '../components/ManagementTable'
import {
getApps,
updateStopRisk,
countLiveCountry,
updateAppShow,
deleteApp,
} from "../api/apiCalls";
import VisibilityIcon from "#material-ui/icons/Visibility";
import DeleteIcon from "#material-ui/icons/Delete";
import EditIcon from "#material-ui/icons/Edit";
import Switch from "#material-ui/core/Switch";
import DeleteModal from "../components/DeleteModal";
import { Link } from "react-router-dom";
const Management = () => {
const [apps, setApps] = useState([]);
const [modalVisible, setModalVisible] = useState(false);
const [currentApp, setCurrentApp] = useState("");
const [appID, setAppID] = useState(0);
const fetchData = useCallback(async () => {
const { data: appsResponse } = await getApps();
const countLiveCountries = await fetchLiveCountriesForApps(appsResponse);
setApps(
appsResponse.map((app, idx) => ({
...app,
countLiveCountry: countLiveCountries[idx],
}))
);
}, []);
useEffect(() => {
fetchData();
}, [fetchData]);
const fetchLiveCountriesForApps = async (appwLive) => {
const countLiveCountries = await Promise.all(
appwLive.map((app) => countLiveCountry(app.appID))
);
return countLiveCountries.map(({ data: liveCountries }) => liveCountries);
};
const removeApp = async () => {
await deleteApp(appID);
setModalVisible(false);
fetchData();
};
const onClickCancel = () => {
setModalVisible(false);
};
const columns = useMemo(() => [
{
Header: "Application Name",
accessor: "app_name",
},
{
Header: "Business Area",
accessor: "businessarea.businessarea_name",
},
{
Header: "Live Plants",
accessor: "countLiveCountry",
},
{
Header: "Line Stop Risk",
accessor: "app_stoprisk",
Cell: ({ row: { original } }) => {
const changeCheck = async (id) => {
await updateStopRisk(id);
fetchData();
};
return (
<input
checked={original.app_stoprisk}
onClick={() => {
changeCheck(original.appID);
}}
id="appStopRisk"
type="checkbox"
style={{ width: 18, height: 18, marginTop: 5 }}
/>
)
},
sortType: (a, b, id) => {
if (a.original[id] > b.original[id]) return -1;
if (b.original[id] > a.original[id]) return 1;
},
},
{
Header: "Actions",
Cell: ({ row: { original } }) => {
const changeTrack = async (id) => {
await updateAppShow(id);
fetchData();
};
return (
<>
<Link
className="btn btn-manage-link btn-sm col-2"
to={{
pathname: `/management/${original.app_name}`,
mode: "view",
id: original.appID
}}
>
<VisibilityIcon></VisibilityIcon>
</Link>
<Link
to={{
pathname: `/management/${original.app_name}`,
mode: "edit",
id: original.appID
}}
className="btn btn-manage-link btn-sm col-2"
>
<EditIcon></EditIcon>
</Link>
<button
onClick={() => {
setModalVisible(true);
setCurrentApp(original.app_name);
setAppID(original.appID);
}}
className="btn btn-manage-link btn-sm col-3"
>
<DeleteIcon></DeleteIcon>
</button>
<Switch
onClick={() => changeTrack(original.appID)}
checked={original.app_show}
className="col-3"
></Switch>
</>
)
},
},
],
[fetchData]
);
return (
<div className="container">
<h2 style={{ float: "left", font: "bold" }}>Management</h2>
<div style={{ float: "right" }}>
<Link className="btn btn-danger btn-sm" to={{ pathname: `/management/add`, mode: "add" }}>
Add New App
</Link>
<Link className="btn btn-danger btn-sm ml-3" exact to="/management/plants">
Plant Management
</Link>
</div>
<ManagementTable columns={columns} data={apps} />
<DeleteModal
message={<strong>{currentApp}</strong>}
variety="app"
onClickCancel={onClickCancel}
onClickOk={removeApp}
visible={modalVisible}
/>
</div>
);
};
export default Management;
The page where I transfer the props.
import React, { useState, useEffect } from "react";
import Accordion from "../components/Accordion";
import Details from '../components/Details'
import {
getByIdApps,
} from "../api/apiCalls";
const ApplicationManagement = (props) => {
const [appById, setAppById] = useState([]);
const { id } = props.location;
const [selectOption, setSelectOption] = useState('add')
useEffect(() => {
getData();
getMode();
}, [])
const getData = async () => {
console.log(props.location.id)
if (props.location.id) {
await getByIdApps(props.location.id).then((response) => setAppById(response.data))
console.log(appById)
console.log(props)
}
else {
setSelectOption('add')
}
}
const getMode = () => props.location.mode ? setSelectOption(props.location.mode) : setSelectOption('add')
const handleOptionChange = (event) => {
console.log(event.target.value)
setSelectOption(event.target.value)
}
return (
<>
<div style={{ margin: 20 }}>
<h1>
{appById.app_shortcode} - {appById.app_fullname}
</h1>
<div className="float-right mb-auto">
<label><input type="radio" value="view" checked={selectOption === 'view'} onChange={handleOptionChange} />View</label>
<label> <input type="radio" value="add" checked={selectOption === 'add'} onChange={handleOptionChange} />Add</label>
<label> <input type="radio" value="edit" checked={selectOption === 'edit'} onChange={handleOptionChange} />Edit</label>
</div>
<br></br>
<div style={{ marginLeft: 50, marginRight: 50 }} >
<Accordion
title={
<div style={{ width: 1350 }}>
<h3>Details</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}
content={
<Details appID={id} data = {appById}></Details>
}
/>
<Accordion title={
<div style={{ width: 1350 }}>
<h3>Links</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}></Accordion>
<Accordion title={
<div style={{ width: 1350 }}>
<h3>Factory Management</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}></Accordion>
<Accordion title={
<div style={{ width: 1350 }}>
<h3>Issues Management</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}></Accordion>
<Accordion title={
<div style={{ width: 1350 }}>
<h3>Middleware Management</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}></Accordion>
</div>)
{selectOption === 'add' ? (
<div>
Add Mode
</div>
) : selectOption === 'view' ? (<div>View Mode</div>) : (<div>eidt</div>)}
</div>
</>
);
};
export default ApplicationManagement;
and the section where the details are kept on the ApplicationManagement page (My code is quite long, I just share the problem part.)
import React, { useState, useEffect } from 'react'
import axios from "axios";
import {
getResponsibleTeams,
getBusinessAreas
} from '../api/apiCalls'
const Details = (props) => {
const [rTeams, setrTeams] = useState([]);
const [bAreas, setbAreas] = useState([]);
const { data } = props;
useEffect(() => {
async function fetchData() {
const getrTeams = await getResponsibleTeams();
const getbAreas = await getBusinessAreas();
axios.all([getrTeams, getbAreas]).then(
axios.spread((...allData) => {
const allrTeams = allData[0].data;
const allbAreas = allData[1].data;
setrTeams(allrTeams);
setbAreas(allbAreas);
})
);
}
fetchData();
}, []);
return (
<div>
<div
style={{
float: "left",
width: 1350,
height: 340,
}}
>
<div className="form-group">
<label style={{ float: "left" }} htmlFor="appFullName">
Frontend:{" "}
</label>
<input
id="appFullName"
type="text"
class="form-control"
placeholder="dsfdsdsf"
value={data.frontend.frontend_name} // error here
//onChange={handleInputChange}
name="appShortCode"
style={{ width: 400, marginLeft: 150 }}
/>
</div>
</div>
</div>
)
}
export default Details;
Later I realized that using asynchronous functions caused some problems. I came up with a solution to this and the problem was solved.
Error Code Here :
<Accordion
title={
<div style={{ width: 1350 }}>
<h3>Details</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}
content={
<Details appID={id} data = {appById}></Details>
}
/>
and the solution to the problem
{appById &&
<Accordion
title={
<div style={{ width: 1350 }}>
<h3>Details</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}
content={
<Details appID={id} data = {appById}></Details>
}
/>}

How to submit the form so that it is displayed in the table?

I created a form at the top that allows the user to enter in a first name, last name, and phone number and submit button.
Once the submit button is pressed, the information should be displayed in a table below (automatically sorted by last name) along with all the previous information that was entered.
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
const style = {
table: {
borderCollapse: 'collapse'
},
tableCell: {
border: '1px solid gray',
margin: 0,
padding: '5px 10px',
width: 'max-content',
minWidth: '150px'
},
form: {
container: {
padding: '20px',
border: '1px solid #F0F8FF',
borderRadius: '15px',
width: 'max-content',
marginBottom: '40px'
},
inputs: {
marginBottom: '5px'
},
submitBtn: {
marginTop: '10px',
padding: '10px 15px',
border:'none',
backgroundColor: 'lightseagreen',
fontSize: '14px',
borderRadius: '5px'
}
}
}
function PhoneBookForm({ addEntryToPhoneBook }) {
return (
<form onSubmit={ e => { e.preventDefault() }} style={style.form.container}>
<label>First name:</label>
<br />
<input
style={style.form.inputs}
className='userFirstname'
name='userFirstname'
type='text'
value='Coder'
/>
<br/>
<label>Last name:</label>
<br />
<input
style={style.form.inputs}
className='userLastname'
name='userLastname'
type='text'
value='Byte'
/>
<br />
<label>Phone:</label>
<br />
<input
style={style.form.inputs}
className='userPhone'
name='userPhone'
type='text'
value='8885559999'
/>
<br/>
<input
style={style.form.submitBtn}
className='submitButton'
type='submit'
value='Add User'
/>
</form>
)
}
function InformationTable(props) {
return (
<table style={style.table} className='informationTable'>
<thead>
<tr>
<th style={style.tableCell}>First name</th>
<th style={style.tableCell}>Last name</th>
<th style={style.tableCell}>Phone</th>
</tr>
</thead>
</table>
);
}
function Application(props) {
return (
<section>
<PhoneBookForm />
<InformationTable />
</section>
);
}
ReactDOM.render(
<Application />,
document.getElementById('root')
);
// .....
// .....
// You should have a state where you can store the value of the form to pass it
// to the other component
// I just summarize the code.
function PhoneBookForm(props) {
const [firstname, setFirstname] = useState('');
// const [lastname, setLastname] = useState('');
submitForm(){
// you can do other things about the values of state
props.saveFn({ firstname : firstname });
}
return (
<form onSubmit={ e => { e.preventDefault() }} style={style.form.container}>
<label>First name:</label>
<br />
<input
style={style.form.inputs}
className='userFirstname'
name='userFirstname'
type='text'
onChange={e => setFirstname(e.target.value)}
value={firstname}
/>
<br/>
<input
style={style.form.submitBtn}
className='submitButton'
type='submit'
value='Add User'
onClick={ submitForm }
/>
</form>
)
}
function InformationTable(props) {
return (
<table style={style.table} className='informationTable'>
<thead>
<tr>
<th style={style.tableCell}>First name</th>
</tr>
{
props.Items.map((item,idx) => <tr style={style.tableCell} key={idx}> <td>{item.firstname} </td></tr>)
}
</thead>
</table>
);
}
function Application(props) {
const [items, setItems] = useState([]);
function addItem(newItem){
let sorted_item = [];
// add newItem here and
// sort your items here
setItems(sorted_item)
}
return (
<section>
<PhoneBookForm saveFn={addItem}/>
<InformationTable Items={items}/>
</section>
);
}
ReactDOM.render(
<Application />,
document.getElementById('root')
);
There are several ways to do this. I only fix the Name for you and let you figure out the rest. So basically you have to create a state (useState) in your parent component (Application) and pass it down to via props to the two children components (PhoneBookForm and InformationTable). In the PhoneBookForm, you call the addEntryToPhoneBook function to update the state (i.e. adding names to the phonebook. In the InformationTable, you only have to render the state addEntryToPhoneBook from parent compnent.
https://i.imgur.com/lzWzKj0.png
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
const style = {
table: {
borderCollapse: 'collapse'
},
tableCell: {
border: '1px solid gray',
margin: 0,
padding: '5px 10px',
width: 'max-content',
minWidth: '150px'
},
form: {
container: {
padding: '20px',
border: '1px solid #F0F8FF',
borderRadius: '15px',
width: 'max-content',
marginBottom: '40px'
},
inputs: {
marginBottom: '5px'
},
submitBtn: {
marginTop: '10px',
padding: '10px 15px',
border: 'none',
backgroundColor: 'lightseagreen',
fontSize: '14px',
borderRadius: '5px'
}
}
}
function PhoneBookForm(props) {
//Create a function to handle when info is submit.
const handleFirstName = (e) => {
e.preventDefault();
//Updating the state of the parent using spread operator.
//This is a standard way to update state since it's immutatble.
//i.e. you update it via making a copy and adding new info
props.addEntryToPhoneBook([...props.phoneBook, document.getElementById('firstName').value]);
}
return (
<form style={style.form.container}>
<label>First name:</label>
<br />
{/*Note: replace value with placeholder because value need to be able to change.*/}
<input
id='firstName'
style={style.form.inputs}
className='userFirstname'
name='userFirstname'
type='text'
placeholder='Coder'
/>
<br />
<label>Last name:</label>
<br />
<input
style={style.form.inputs}
className='userLastname'
name='userLastname'
type='text'
placeholder='Byte'
/>
<br />
<label>Phone:</label>
<br />
<input
style={style.form.inputs}
className='userPhone'
name='userPhone'
type='text'
placeholder='8885559999'
/>
<br />
<input
onClick={handleFirstName}
style={style.form.submitBtn}
className='submitButton'
type='submit'
placeholder='Add User'
/>
</form>
)
}
function InformationTable({ phoneBook }) {
return (
<table style={style.table} className='informationTable'>
<thead>
<tr>
<th style={style.tableCell}>First name</th>
<th style={style.tableCell}>Last name</th>
<th style={style.tableCell}>Phone</th>
</tr>
</thead>
{/*Rendering the info in phoneBook via mapping*/}
{
phoneBook.map(data =>
<tr key={data}>
<th>
{data}<br />
</th>
</tr>
)}
</table>
);
}
function Application() {
//Create a state here to store all your data in the phonebook.
const [phoneBook, addEntryToPhoneBook] = useState([]);
console.log('userInfo parent: ', phoneBook)
//Since you have to pass down two props, you can use objects like this.
let props = {
phoneBook: phoneBook,
addEntryToPhoneBook: addEntryToPhoneBook
}
return (
<section>
{/*Passing down two props using spread operator*/}
<PhoneBookForm {...props} />
{/*Only passing down one prop here because you're don't need to display the data.*/}
<InformationTable phoneBook={phoneBook} />
</section>
);
}
export default Application;

React-table and go to first/last page

I'm trying to add "go to" first/last page buttons to the React-Table by overwriting PreviousComponent and NextComponent but it looks like both components are connected to the previous/next page functionality behaviours.
Is there any other way to add those two buttons to the default pagination component?
You can customise the text as required. I have mocked the data, you can pass the actual data as required
See the code
App.js
import React from "react";
import styled from "styled-components";
import { useTable, usePagination } from "react-table";
import makeData from "./makeData";
const Styles = styled.div`
padding: 1rem;
table {
border-spacing: 0;
border: 1px solid black;
tr {
:last-child {
td {
border-bottom: 0;
}
}
}
th,
td {
margin: 0;
padding: 0.5rem;
border-bottom: 1px solid black;
border-right: 1px solid black;
:last-child {
border-right: 0;
}
}
}
.pagination {
padding: 0.5rem;
}
`;
function Table({ columns, data }) {
// Use the state and functions returned from useTable to build your UI
const {
getTableProps,
getTableBodyProps,
headerGroups,
prepareRow,
page, // Instead of using 'rows', we'll use page,
// which has only the rows for the active page
// The rest of these things are super handy, too ;)
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
state: { pageIndex, pageSize }
} = useTable(
{
columns,
data,
initialState: { pageIndex: 2 }
},
usePagination
);
// 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()}>
{page.map((row, i) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return (
<td {...cell.getCellProps()}>{cell.render("Cell")}</td>
);
})}
</tr>
);
})}
</tbody>
</table>
{/*
Pagination can be built however you'd like.
This is just a very basic UI implementation:
*/}
<div className="pagination">
<button onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
{"First"}
</button>{" "}
<button onClick={() => previousPage()} disabled={!canPreviousPage}>
{"<"}
</button>{" "}
<button onClick={() => nextPage()} disabled={!canNextPage}>
{">"}
</button>{" "}
<button onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
{"Last"}
</button>{" "}
<span>
Page{" "}
<strong>
{pageIndex + 1} of {pageOptions.length}
</strong>{" "}
</span>
<span>
| Go to page:{" "}
<input
type="number"
defaultValue={pageIndex + 1}
onChange={e => {
const page = e.target.value ? Number(e.target.value) - 1 : 0;
gotoPage(page);
}}
style={{ width: "100px" }}
/>
</span>{" "}
<select
value={pageSize}
onChange={e => {
setPageSize(Number(e.target.value));
}}
>
{[10, 20, 30, 40, 50].map(pageSize => (
<option key={pageSize} value={pageSize}>
Show {pageSize}
</option>
))}
</select>
</div>
</>
);
}
function App() {
const columns = React.useMemo(
() => [
{
Header: "Name",
columns: [
{
Header: "First Name",
accessor: "firstName"
},
{
Header: "Last Name",
accessor: "lastName"
}
]
},
{
Header: "Info",
columns: [
{
Header: "Age",
accessor: "age"
},
{
Header: "Visits",
accessor: "visits"
},
{
Header: "Status",
accessor: "status"
},
{
Header: "Profile Progress",
accessor: "progress"
}
]
}
],
[]
);
const data = React.useMemo(() => makeData(100000), []);
return (
<Styles>
<Table columns={columns} data={data} />
</Styles>
);
}
export default App;
Working codesandbox
For v6 I have ended up overwriting PaginationComponent
<ReactTable
....
PaginationComponent={PaginationComponent}
....
>
with modified default code as custom PaginationComponent where I have added
<div className="-first">
<button
disabled={!canPrevious}
onClick={() => {
if (!canPrevious) return
this.changePage(0)
}}
> First </button>
</div>
and
<div className="-last">
<button
onClick={() => {
if (!canNext) return
this.changePage(pages)
}}
disabled={!canNext}
> Last </button>
</div>

Resources