import React,{Component} from 'react'
class Todo extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
fetchdata: [],
};
}
componentDidMount() {
fetch("https://jsonplaceholder.typicode.com/todos")
.then((res) => res.json())
.then((json) => {
this.setState({
data: json,
});
});
}
componentDidUpdate(){
this.fetchdata();
}
fetchdata=()=>{
fetch("https://jsonplaceholder.typicode.com/users/:id")
.then((res) => res.json())
.then((json) => {
this.setState({
fetchdata: json.data,
});
});
}
render() {
const { data, fetchdata } = this.state;
return (
<div>
<div className="Todos row g-3">
<table class="table col-auto">
<thead>
<tr>
<th scope="col">Todo</th>
<th scope="col">Title</th>
<th scope="col">Status</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
{this.state.data.map((data, index) => (
<tr key={index}>
<th scope="row">{data.id}</th>
<td>{data.title}</td>
<td>{data.completed}</td>
<td>
<button onClick={this.fetchdata.bind(this, data)}>
View
</button>
</td>
</tr>
))}
;
</tbody>
</table>
</div>
<div className="show-data col-auto">
<table class="table table-striped">
<thead>
<tr>
<th scope="col">Todo_Id</th>
<th scope="col">Todo_title</th>
<th scope="col">User_id</th>
</tr>
</thead>
<tbody>
{this.state.fetchdata.map((fetchdata, index) => (
<tr key={index}>
<th scope="row">{fetchdata.id}</th>
<td>{fetchdata.name}</td>
<td>{fetchdata.email}</td>
</tr>
))}
;
</tbody>
</table>
</div>
</div>
);
}
}
export default Todo
This is my code I want to load data on button click but I am getting an error: "Cannot read properties of undefined (reading 'map') ". I am new to react js and don't know how to do it. The data is not getting loaded in the below table on button click by id. The first table data is loading correctly.
There were few issues
id was not passed as a param to fetchdata
respnse data was JSON not an Array
DO NOT call any function in componentDidUpdate without checking prev state. There was an infinite loop calling the API.
No need to bind fetchdata function as it is an arrow function.
import React, { Component } from "react";
class Todo extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
fetchdata: []
};
}
componentDidMount() {
fetch("https://jsonplaceholder.typicode.com/todos")
.then((res) => res.json())
.then((json) => {
this.setState({
data: json
});
});
}
fetchdata = (id) => {
console.log(id);
fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
.then((res) => res.json())
.then((json) => {
console.log(json);
this.setState({
fetchdata: json
});
});
};
render() {
const { data, fetchdata } = this.state;
return (
<div>
<div className="Todos row g-3">
<table class="table col-auto">
<thead>
<tr>
<th scope="col">Todo</th>
<th scope="col">Title</th>
<th scope="col">Status</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
{this.state.data.map((data, index) => (
<tr key={index}>
<th scope="row">{data.id}</th>
<td>{data.title}</td>
<td>{data.completed}</td>
<td>
<button onClick={() => this.fetchdata(data.id)}>
View
</button>
</td>
</tr>
))}
;
</tbody>
</table>
</div>
<div className="show-data col-auto">
<table class="table table-striped">
<thead>
<tr>
<th scope="col">Todo_Id</th>
<th scope="col">Todo_title</th>
<th scope="col">User_id</th>
</tr>
</thead>
<tbody>
{this.state.fetchdata && (
<tr>
<th scope="row">{fetchdata.id}</th>
<td>{fetchdata.name}</td>
<td>{fetchdata.email}</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
);
}
}
export default Todo;
Sandbox code => https://codesandbox.io/s/pensive-parm-c0l54?file=/src/App.js:0-2277
If you are new to react i highly recommend you to use hooks, but there are several things you can do in your Code:
1-Fetch data(you need id i Think, so):
fetchdata=(id)=>{
fetch(https://jsonplaceholder.typicode.com/users/${id})
.then((res) => res.json())
.then((json) => {
this.setState({
fetchdata: json.data,
});
});
}
This Way you pass the id by arguments.
2- onClick función:
View
As you Will need the id to pass it to the fetch función. No need bina with fan Arrow function
3- This is the Code i suggest for hooks:
import React, {useState, useEffect} from "react";
const Todo = () => {
const [data, setData] = useState([])
const [fetchdata,setFetchdata] = useState([])
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos")
.then((res) => res.json())
.then((json) => {
setData(json);
});
},[])
const fetchdataById = (id) => {
console.log(id);
fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
.then((res) => res.json())
.then((json) => {
console.log(json);
setFetchdata(json)
});
};
return (
<div>
<div className="Todos row g-3">
<table class="table col-auto">
<thead>
<tr>
<th scope="col">Todo</th>
<th scope="col">Title</th>
<th scope="col">Status</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
{data.map((data, index) => (
<tr key={index}>
<th scope="row">{data.id}</th>
<td>{data.title}</td>
<td>{data.completed}</td>
<td>
<button onClick={() => fetchdataById(data.id)}>
View
</button>
</td>
</tr>
))}
;
</tbody>
</table>
</div>
<div className="show-data col-auto">
<table class="table table-striped">
<thead>
<tr>
<th scope="col">Todo_Id</th>
<th scope="col">Todo_title</th>
<th scope="col">User_id</th>
</tr>
</thead>
<tbody>
{fetchdata && (
<tr>
<th scope="row">{fetchdata.id}</th>
<td>{fetchdata.name}</td>
<td>{fetchdata.email}</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
);
}
export default Todo;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Something like this should Work,
here's what you can do:
class Todo extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
fetchdata: {}
};
}
componentDidMount() {
fetch("https://jsonplaceholder.typicode.com/todos")
.then((res) => res.json())
.then((json) => {
this.setState({
data: json
});
});
}
fetchdata = (todo) => {
fetch("https://jsonplaceholder.typicode.com/users/" + todo.id)
.then((res) => res.json())
.then((json) => {
this.setState({
fetchdata: json
});
});
};
render() {
const { data, fetchdata } = this.state;
return (
<div>
<div className="Todos row g-3">
<table className="table col-auto">
<thead>
<tr>
<th scope="col">Todo</th>
<th scope="col">Title</th>
<th scope="col">Status</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
{data.map((todo, index) => (
<tr key={index}>
<th scope="row">{todo.id}</th>
<td>{todo.title}</td>
<td>{todo.completed}</td>
<td>
<button onClick={() => this.fetchdata(todo)}>View</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
<div className="show-data col-auto">
<table className="table table-striped">
<thead>
<tr>
<th scope="col">Todo_Id</th>
<th scope="col">Todo_title</th>
<th scope="col">User_id</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">{fetchdata.id}</th>
<td>{fetchdata.name}</td>
<td>{fetchdata.email}</td>
</tr>
</tbody>
</table>
</div>
</div>
);
}
}
ReactDOM.render(
<Todo />,
document.body
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Related
I created a table on(table.js) with 4 different endpoints(app.js) I would like to add a refresh button that will refresh the data when clicked on. How would I do that with 4 different endpoints? I did try the interval but it refreshed the whole page.
This is my App.file where the data was fetched from.
function App() {
const [feed, setFeed] = useState([]);
const [feedol, setFeedol] = useState([]);
const [jsonData, setJsonData] = useState([]);
const [azureData, setAzureData] = useState([]);
useEffect(() => {
fetch("/feed").then((response) =>
response.json().then((data) => {
setFeed(data);
})
);
}, []);
useEffect(() => {
fetch("/feed_ol").then((response) =>
response.json().then((data) => {
setFeedol(data);
})
);
}, []);
useEffect(() => {
fetch("/json_data").then((response) =>
response.json().then((data) => {
setJsonData(data["archive"][0]);
})
);
}, []);
useEffect(() => {
fetch("/azure_data").then((response) =>
response.json().then((data) => {
setAzureData(data);
})
);
}, []);
Table.js
import React from "react";
import { Card, Container } from "react-bootstrap";
import { BsArrowClockwise } from "react-icons/bs";
import Cards from "./Cards";
import "./tables.css";
export const Tables = ({ feed, feedol, jsonData, azureData, refresh
}) => {
return (
<Container>
<Cards />
<Card className="table-card">
<Card.Header>
{" "}
<button type="button" className=" refresh-button" onClick=
{}>
{" "}
<BsArrowClockwise />
</button>{" "}
OneLogin Outages{" "}
</Card.Header>
<Card.Body>
<table className="table table-bordered">
<thead>
<tr>
<th>Title</th>
<th>Link</th>
<th>Date</th>
</tr>
</thead>
<tbody>
<tr>
<td>{feedol.title}</td>
<td>{feedol.link}</td>
<td>{feedol.updated}</td>
</tr>
<tr>
<td>{}</td>
<td>{}</td>
<td>{}</td>
</tr>
<tr>
<td>{jsonData.service_name}</td>
<td>{jsonData.summary}</td>
<td>{jsonData.date}</td>
</tr>
</tbody>
</table>
</Card.Body>
</Card>
<Cards />
<Card className="table-card">
<Card.Header> Unifi Outages </Card.Header>
<Card.Body>
<table className="table table-bordered">
<thead>
<tr>
<th>Title</th>
<th>Link</th>
<th>Date</th>
</tr>
</thead>
<tbody>
<tr>
<td>{feed.title}</td>
<td>{feed.link}</td>
<td>{feed.updated}</td>
</tr>
<tr>
<td>{}</td>
<td>{}</td>
<td>{}</td>
</tr>
<tr>
<td>{azureData.title}</td>
<td>{azureData.link}</td>
<td>{azureData.updated}</td>
</tr>
</tbody>
</table>
</Card.Body>
</Card>
</Container>
);
};
It doesn't matter how complex the refresh is, put it all in one function:
const App = () => {
const fetchAndSet = () => {
// all the fetch and sets
}
useEffect(() => { fetchAndSet(); }, []);
return <Table refresh={fetchAndSet} />;
}
If your fetch action depends on a click, do not use useEffect as useEffect is intended to be used to synchronize state.
const URLS = {
feed: '/feed',
feedol: '/feed_ol',
jsonData: '/json_data',
azureData: '/azure_data'
}
function App() {
const [data, setData] = useState({
feed: [],
feedol: [],
jsonData: [],
azureData: []
})
//reusable function
const handleFetch = (type) => {
fetch(URLS[type]).then((response) =>
response.json().then((data) => {
setData(d => ({
...d, [type]: data
}));
})
}
//Table.js
import React from "react";
import { Card, Container } from "react-bootstrap";
import { BsArrowClockwise } from "react-icons/bs";
import Cards from "./Cards";
import "./tables.css";
export const Tables = ({ feed, feedol, jsonData, azureData, handleFetch
}) => {
return (
<Container>
<Cards />
<Card className="table-card">
<Card.Header>
{" "}
<button type="button" className=" refresh-button" onClick={
() => {Object.keys(URLS).map(handleFetch)}
}>
{" "}
<BsArrowClockwise />
</button>{" "}
OneLogin Outages{" "}
</Card.Header>
<Card.Body>
<table className="table table-bordered">
<thead>
<tr>
<th>Title</th>
<th>Link</th>
<th>Date</th>
</tr>
</thead>
<tbody>
<tr>
<td>{feedol.title}</td>
<td>{feedol.link}</td>
<td>{feedol.updated}</td>
</tr>
<tr>
<td>{}</td>
<td>{}</td>
<td>{}</td>
</tr>
<tr>
<td>{jsonData.service_name}</td>
<td>{jsonData.summary}</td>
<td>{jsonData.date}</td>
</tr>
</tbody>
</table>
</Card.Body>
</Card>
<Cards />
<Card className="table-card">
<Card.Header> Unifi Outages </Card.Header>
<Card.Body>
<table className="table table-bordered">
<thead>
<tr>
<th>Title</th>
<th>Link</th>
<th>Date</th>
</tr>
</thead>
<tbody>
<tr>
<td>{feed.title}</td>
<td>{feed.link}</td>
<td>{feed.updated}</td>
</tr>
<tr>
<td>{}</td>
<td>{}</td>
<td>{}</td>
</tr>
<tr>
<td>{azureData.title}</td>
<td>{azureData.link}</td>
<td>{azureData.updated}</td>
</tr>
</tbody>
</table>
</Card.Body>
</Card>
</Container>
);
};
I'm trying to get data of a table to modal, I got a table and all data are populated just fine, I got a button next to each row where I will like that when I click the button I display all data from the selected row. I got to manage to get the data with console.log, but I cannot get it to render in the modal. I got no errors but still it doesn't show either. I've attached an image with what i got. as you in the console. I get the select row
customsite.jsx
import React, { useState } from 'react';
import Modal from './reusable/modal';
import useFetchData from './hooks/useFetchData';
const Customsite = ()=> {
const {
data,
loading,
} = useFetchData();
const [display, openModal] = useState(false);
const closeModal = () =>{
openModal(false);
}
const openedModal = () =>{
openModal(true);
}
const getAllData = (data) =>{
console.log(data);
return data;
}
return(
<div>
<div className='conatiner'>
<table className="table">
<thead>
<tr>
<th>id</th>
<th>titel</th>
<th>body</th>
<th>actions</th>
<th>details</th>
</tr>
</thead>
<tbody>
{data.map(posts =>(
<tr key={posts.id}>
<th>{posts.id}</th>
<th>{posts.title}</th>
<th>{posts.body}</th>
<th><button className="btn btn-primary"
onClick={()=> { getAllData(posts); openedModal();}}>
button</button>
</th>
<th>
<button
className="btn btn-success">Success</button>
</th>
</tr>
))}
</tbody>
</table>
<Modal isOpened={display}
closeModal ={closeModal} >
<h1>modal header</h1>
<p>{getAllData}</p>
</Modal>
</div>
</div>
)
}
export default Customsite
Here getAllData is a function that holds the value of the data so by directly calling that inside the <p> tag it will not print the data.
import React, { useState } from 'react';
import Modal from './reusable/modal';
import useFetchData from './hooks/useFetchData';
const Customsite = ()=> {
const {
data,
loading,
} = useFetchData();
const [display, openModal] = useState(false);
const [seletcedData, setSelectedData] = useState();
const closeModal = () =>{
openModal(false);
}
const openedModal = () =>{
openModal(true);
}
const getAllData = (data) =>{
console.log(data);
setSelectedData(data);
openedModal();
}
return(
<div>
<div className='conatiner'>
<table className="table">
<thead>
<tr>
<th>id</th>
<th>titel</th>
<th>body</th>
<th>actions</th>
<th>details</th>
</tr>
</thead>
<tbody>
{data.map(posts =>(
<tr key={posts.id}>
<th>{posts.id}</th>
<th>{posts.title}</th>
<th>{posts.body}</th>
<th><button className="btn btn-primary"
onClick={()=> { getAllData(posts);}}>
button</button>
</th>
<th>
<button
className="btn btn-success">Success</button>
</th>
</tr>
))}
</tbody>
</table>
{display &&
<Modal isOpened={display}
closeModal ={closeModal} >
<h1>modal header</h1>
<p>{selectedData?.title}</p>
</Modal>
}
</div>
</div>
)
}
export default Customsite
Here is the solution and you can create multiple <p> tags to display the required data.
make a state for data
const [tableData, setTableData] = useState({})
after fetching data :
const getAllData = (data) =>{
setTableData(data)
console.log(data);
}
then on Modal:
<Modal isOpened={display}
closeModal ={closeModal} >
<h1>{tableData.title}</h1>
<p>{tableData.body}</p>
</Modal>
Try like this
import React, { useState } from "react";
import Modal from "./reusable/modal";
import useFetchData from "./hooks/useFetchData";
const Customsite = () => {
const { data, loading } = useFetchData();
const [display, openModal] = useState(false);
const [rowData, setRowData] = useState();
const closeModal = () => {
openModal(false);
};
const openedModal = () => {
openModal(true);
};
return (
<div>
<div className="conatiner">
<table className="table">
<thead>
<tr>
<th>id</th>
<th>titel</th>
<th>body</th>
<th>actions</th>
<th>details</th>
</tr>
</thead>
<tbody>
{data.map((posts) => (
<tr key={posts.id}>
<th>{posts.id}</th>
<th>{posts.title}</th>
<th>{posts.body}</th>
<th>
<button
className="btn btn-primary"
onClick={() => {
setRowData(posts);
openedModal();
}}
>
button
</button>
</th>
<th>
<button className="btn btn-success">Success</button>
</th>
</tr>
))}
</tbody>
</table>
<Modal isOpened={display} closeModal={closeModal}>
<div>
<h1>modal header</h1>
<table className="table">
<thead>
<tr>
<th>id</th>
<th>titel</th>
<th>body</th>
</tr>
</thead>
<tbody>
{
<tr key={rowData?.id}>
<th>{rowData?.id}</th>
<th>{rowData?.title}</th>
<th>{rowData?.body}</th>
</tr>
}
</tbody>
</table>
</div>
</Modal>
</div>
</div>
);
};
export default Customsite;
I'm getting data from my API, when I make a console.log or JSON.stringify in the API data it shows without problems but when I pass the data in a table with the map, simply nothing is presented in the table. .
const [users, setUsers] = useState([]);
const loadUser = () => {
getUsers().then(data => {
if(data.error) {
console.log(data.error)
}else{
setUsers(data)
}
})
}
const inforUsers = () => {
return(
<Fragment>
<table className="table table-bordered mb-5">
<thead className="thead-dark">
<tr>
<th scope="col">Id</th>
<th scope="col">Nome</th>
<th scope="col">Email</th>
<th scope="col">role</th>
<th scope="col">createdAt</th>
</tr>
</thead>
<tbody scope="row">
{Object.keys(users).map((values, key) => (
<tr key={key}>
<td>
{values._id}
</td>
<td>
{values.name}
</td>
<td>
{values.email}
</td>
<td>
{values.role === 1? 'Admin' : 'Simples User'}
</td>
<td>
{values.createdAt}
</td>
</tr>
))}
</tbody>
</table>
</Fragment>
)
}
I think you are confused about the data you have in hand. The key is the id for each object, so if you want that data, you should access the users object by each of the keys/ids you get from Object.keys. A brief example:
{Object.keys(users).map(id => (
{users[id]._id}
))}
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 have one object array say defect and now if the status of the defect is open then it should show as button and it should read close the defect and if it is closed, then instead as button it should just mention as closed.
So, here statusRender is the issue and is now working as expected in the last column. Cant figure out what I am missing. Any leads?
render() {
if (defect.defect_status == 'open') {
statusRender = <button key={index} data-id={defect.id} onClick={() => this.showAlert(defect.defect_id)}>{defect.defect_status}</button>;
} else {
statusRender = { defect.defect_status };
}
return (
<div>
<table className="table table-bordered table-hover">
<thead>
<tr>
<th>Defect ID</th>
<th>Category</th>
<th>Description</th>
<th>Priority</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{this.state.defectList.map((defect, index) => {
return (
<tr key={index}>
<td> {defect.defect_id} </td>
<td>{defect.defect_category}</td>
<td>{defect.defect_description}</td>
<td>{defect.defect_priority}</td>
<td> {statusRender}
</td>
</tr>
);
})
}
</tbody>
</table>
</div>
)
}
it is a scope issue you cannot declare defect outside of the map function
{this.state.defectList.map((defect,index) => {
return (
<tr key={index}>
<td> {defect.defect_id} </td>
<td>{defect.defect_category}</td>
<td>{ defect.defect_description}</td>
<td>{ defect.defect_priority}</td>
<td>
{
defect.defect_status === 'open'
? <button key={index} data-id={defect.id} onClick = {() => this.showAlert(defect.defect_id)}>{defect.defect_status}</button>;
: defect.defect_status;
}
</td>
</tr>
);
})
}
Thanks to user1095118 removing the semi colons did the job. I was missing the correctness of the curly braces which solved the issue
{
defect.defect_status == 'open'
?<button key={index} data-id={defect.id} onClick = {() => this.showAlert(defect.defect_id)}>{defect.defect_status}</button> : defect.defect_status
}
If you just need to access status string instead of the button maybe you should remove brackets in your if else statement
render() {
if(defect.defect_status=='open') {
statusRender = <button key={index} data-id={defect.id} onClick = {() => this.showAlert(defect.defect_id)}>{defect.defect_status}</button>;
} else {
// No brackets here ?
statusRender = defect.defect_status;
}
return (
<div>
<table className="table table-bordered table-hover">
<thead>
<tr>
<th>Defect ID</th>
<th>Category</th>
<th>Description</th>
<th>Priority</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{this.state.defectList.map((defect,index) =>{
return(
<tr key={index}>
<td> {defect.defect_id} </td>
<td>{defect.defect_category}</td>
<td>{ defect.defect_description}</td>
<td>{ defect.defect_priority}</td>
<td> {statusRender}
</td>
</tr>
);
})
}
</tbody>
</table>
</div>
)
}
}