the example to which I refer is the following:
https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/sub-components
I would like to fetch a json file and pass the elements of the latter into the table instead of generating them as in the previous example.
The instructions for making fetch are clear to me but I can't understand how to integrate them in the "makeData" file.
This is my "makeData" code:
import ReactDOM from 'react-dom';
const range = len => {
const arr = []
for (let i = 0; i < len; i++) {
arr.push(i)
}
return arr
}
const newPerson = () => {
fetch('http://localhost:5000/api/azienda')
.then(res => res.json())
// .then((rows) => {
// ReactDOM.render(this.makeData(rows), document.getElementById('root'));
// });
}
export default function makeData(...lens) {
const makeDataLevel = (depth = 0) => {
const len = lens[depth]
return range(len).map(d => {
return {
...newPerson(),
subRows: lens[depth + 1] ? makeDataLevel(depth + 1) : undefined,
}
})
}
return makeDataLevel()
}
For any advice I will thank you
Create an array in the constructor ,where the data will be stored , fetch the data from the serverlink and then put it in the table
constructor(props, context) {
super(props, context);
this.state = { items: []};
}
getList = () => {
fetch("http://localhost:5000/api/azienda")
.then(res => res.json())
.then(items => this.setState({ items }))
.catch(err => console.log(err));
};
componentDidMount() {
this.getList();
}
Related
I'm using functional component and I'm getting JSOS object from local file And in component I'm setting that JSON in some state.
After that few object I spliced(deleted) from that setState. But again in onchange function I want all the JSON object but here I'm getting updated json means few are deleted, Is there any method I can store all JSON object in some place? can anybody help me in this.
const StudyDetails = () => {
const [supplyPlan, setSupplyPlan] = useState([]);
const getSupplyPlanDetails = useCallback(
async () => {
try {
const payload = {
studyName: studyDetails?.studyName
? studyDetails?.studyName
: query.get("name"),
country: [],
depot: [],
material: [],
site: [],
inTransientMaterial,
};
const res = await getSupplyPlan(payload);
//setSupplyPlan(res);
console.log(res)
// setSupplyPlan(supplyData)
} catch (err) {
setSupplyPlan([]);
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[]
);
useEffect(() => {
getSupplyPlanDetails();
}, [ getSupplyPlanDetails]);
const onChange = (e) => {debugger
console.log(supplyData)
}
return (
<div>
<Checkbox
onChange={onChange}
>
In Transit
</Checkbox>
{supplyPlan?.map((item, index) => (
<Fragment key={index}>
<SupplyChain item={item} />
<Divider className="supply-chain-divider" />
</Fragment>
))}
</div>
)
}
I'm splicing few object in supplyChain component:
const SupplyChain = ({ item }) => {
useEffect(() => {
let data = [];
if (item && item.inTransit.length != 1) {
item &&
item.inTransit &&
item.inTransit.length > 0 &&
item.inTransit.map((intrans, index) => {
if (
intrans.from === item.depots?.packagingDepot?.[0]?.depotName &&
intrans.to === "sites"
) {
let directPath = item.inTransit.splice(index, 1);
setDirectSite(directPath);
}
setFilterJson(item.inTransit);
// eslint-disable-next-line react-hooks/exhaustive-deps
item = { ...item, filterJson: item.inTransit };
});
}
}
So if again when I click on onchange function I want all objects of JSON.
please someone help me in this
I have to fetch 2 api from backend, and try to get the result from this two. but, at the moment, the JSON result I get from the first API is object Array in JSON. I need to pass the id from first API(using setState) to second API for path variables. But when I do in my way, it fail to retrieve the data. Consider the code below:
componentDidMount(){
// console.log(loginEmail)
fetch(`http://localhost:9000/api/item/list`,)
.then((resp)=>{
resp.json().then((res)=>{
console.log(res.data);
// localStorage.setItem('id', res.data.user_info.id);
this.setState({data: res.data});
}
)
})
const id = this.state.data.id;
fetch(`http://localhost:9000/api/item/photo/view/${id}`,)
.then((resp)=>{
resp.json().then((res)=>{
console.log(res);
// localStorage.setItem('id', res.data.user_info.id);
this.setState({res});}
)
})
}
The problem is that fetch returns a Promise so, at the line
const id = this.state.data.id;
You do not have data populated yet.
You have to concatenate the two requests in a way like the following:
componentDidMount() {
fetch(`http://localhost:9000/api/item/list`)
.then((resp) => {
// return the id
})
.then((id) => {
fetch(`http://localhost:9000/api/item/photo/view/${id}`)
.then((resp) => {
// do what you need with the result
})
})
}
Fetch is asynchronous, which means javascript will
fetch data on the first call with no waiting, and continue
to the second fetch call where the id is not defined or Null.
In order to fix that you can use promises as follow
My code example
import React from "react";
class Home extends React.Component {
constructor() {
super();
this.state = {
res: [],
}
}
// http://jsonplaceholder.typicode.com/users
fetchData(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then((resp) => {
resp.json().then((res) => {
console.log(res);
// localStorage.setItem('id', res.data.user_info.id);
resolve(res);
}
)
})
})
}
async componentDidMount() {
let data = await this.fetchData("http://jsonplaceholder.typicode.com/users");
console.log("data :", data);
let id = data[0].id;
console.log("Id :", id);
let newData = await this.fetchData(`http://jsonplaceholder.typicode.com/users/${id}`);
this.setState({ res: newData });
}
render() {
return (
<div>
Call API
</div>
)
}
}
export default Home
Adapted on your code
fetchData(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then((resp) => {
resp.json().then((res) => {
console.log(res.data);
// localStorage.setItem('id', res.data.user_info.id);
resolve(res.data);
}
)
})
})
}
async componentDidMount() {
// console.log(loginEmail)
let data = await this.fetchData("http://localhost:9000/api/item/list");
let id = data.id;
let newData = await this.fetchData(`http://localhost:9000/api/item/photo/view/${id}`);
this.setState({ res: newData });
}
You need to make sure that each id gets its relevant results.
async componentDidMount() {
await fetch(`http://localhost:9000/api/item/list`)
.then(async (resp) => {
let req_ = resp.map((item)=>{
return await fetch(`http://localhost:9000/api/item/photo/view/${item.id}`)
})
let result = Promise.all(req_)
console.log(result)
})
}
I used componentDidUpdate and in it I put a shift method, which is used to delete an object from a JSON array and thereby re-render the displayed posts, but the shift method deletes the first object from the array independently in which the delete button on the post will I press? Is there any possibility, then, to bypass the deletion of the first element in favor of the one that is designated to be deleted?
componentDidUpdate(prevProps, prevState) {
const {posts} = this.props;
const indexPosts = posts.findIndex((post) => post.id === this.state.postId);
if(prevProps.posts !== posts){
this.handleData();
} else if (indexPosts !== -1)
{
this.informationAlert();
const log = posts.splice(indexPosts, 1);
console.log(log);
}
}
EDIT: Actions
export const deletedPost = (id) => (dispatch) => {
axios
.delete(`https://jsonplaceholder.typicode.com/posts/${id}`, id, {
headers: {
'Content-type': 'application/json'
}
})
.then((post) =>
dispatch({
type: DELETED_POST,
payload: post.data
})
)
.catch((err) => console.log(err));
};
import { FETCH_POSTS, NEW_POST, DELETED_POST, FETCH_COMMENTS, NEW_COMMENT } from '../actions/types';
const initialState = {
items: [],
item: {},
itemComent: [],
itemNewComment: {},
deletedPost: []
};
export default function (state = initialState, action) {
switch (action.type) {
case FETCH_POSTS:
return {
...state,
items: action.payload
};
case NEW_POST:
return {
...state,
item: action.payload
};
case DELETED_POST:
return {
...state,
deletedPost: action.payload
};
case FETCH_COMMENTS:
return {
...state,
itemComent: action.payload
}
case NEW_COMMENT:
return {
...state,
itemNewComment: action.payload
}
default:
return state;
}
}
EDIT 2:
const mapStateToProps = (state) => ({
posts: state.posts.items,
newPost: state.posts.item,
deletedPost2: state.posts.deletedPost
});
EDIT 3:
handleDeletedPost = (id) => {
this.setState({
postId: id
})
}
Edit 4:
//I added in constructor
this.state: dataPost: '',
//next I create function to load data and send to state dataPost
handleData = (e) => {
const {posts} = this.props;
const {dataPost} = this.state;
const letang = posts;
const postsData = dataPost;
if (postsData.length <= 0) {
this.setState({
dataPost: letang
})
} else {
console.log('stop')
}
}
// next i create in componentDidUpdate this code
componentDidUpdate(prevProps, prevState) {
const {posts} = this.props;
const indexPosts = posts.findIndex((post) => post.id === this.state.postId);
if(prevProps.posts !== posts){
this.handleData();
} else if (indexPosts !== -1)
{
this.informationAlert();
const log = posts.splice(indexPosts, 1);
console.log(log);
}
}
** When I added loop if (indexPosts !== -1) then my array is cut only one object :-)
API Posts: https://jsonplaceholder.typicode.com/posts/
The results are visible at this link when you press details and then the delete icon: https://scherlock90.github.io/api-post-task/
You need to use splice to delete an element from array.
In splice you need to provide startIndex and number of elements to remove in second argument. In below code find index using `findIndex method, second argument is 1 as we need to remove only 1 element.
Try this
componentDidUpdate (prevProps, prevState) {
if (prevProps.deletedPost) {
const { posts } = this.props
const letang = posts.splice(posts.findIndex( (post)=> post.id === prevProps.deletedPost.id), 1);
console.log(posts); // this should have array without deletedPost
}
}
This might help:
componentDidUpdate (prevProps, prevState) {
if (prevProps.deletedPost) {
const letang = this.props.posts;
letang.splice(deletedPost, 1);
}
}
the slice() takes the index of the object and an optional number of items to delete. since you just want to delete a single object you pass 1.
This might help, try filtering out the object you dont want in the array.
componentDidUpdate (prevProps, prevState) {
if (prevProps.deletedPost) {
const letang = this.props.items.filter(p => p.id !== prevProps.deletedPost.id);
}
}
UPDATED
I think you should be deleting the items in your redux store rather than trying to delete the posts from your api since the api might rather be generating the same data randomly. Change your actionCreator to
export const deletedPost = (id) => {
dispatch({
type: DELETED_POST,
payload: id
});
};
Then use this in your reducer so you can focus on items array coming from your reducer store. Then remove deletedPost: [] from your reducer.
...
case DELETED_POST:
const newItems = state.items.filter(p => p.id !== action.payload);
return {
...state,
items: [ ...newItems ],
};
...
use splice() to delete :), you can find the index of post which should be deleted and then delete it by using this method.
I have a problem with slicing my json. I was using data.json and everything worked fine, but when I'm trying to use the same with fetch. Console tells me that data.slice is not a function. This is my code in React:
const left = '<';
const right = '>';
const { currentPage, usersPerPage } = this.state;
const lastPage = currentPage * usersPerPage;
const firstPage = lastPage - usersPerPage;
const data = fetch('https://jsonplaceholder.typicode.com/photos')
.then(response => response.json());
const currentPhotos = data.slice(firstPage, lastPage);
const renderPhotos = currentPhotos.map((photo) => {
return <tr key={photo.id}>
<td className="number">{photo.title}</td>
</tr>
});
const numbers = [];
for (let i = 1; i <= Math.ceil(data.length / usersPerPage); i++) {
numbers.push(i);
}
const renderPagination = numbers.map(number => {
return (
<li className="controls" key={number} id={number} onClick={this.handlePages}>
{number}
</li>
);
});
fetch is async, which means it returns a promise.
const data = fetch('https://jsonplaceholder.typicode.com/photos')
.then(response => response.json())
.then(json => console.log(json));
the constant data here is a Promise. which awaits to get resolved, to get your code to work you either have to use async/await like this:
const data = await fetch('https://jsonplaceholder.typicode.com/photos')
.then(response => response.json())
.then(json => console.log(json));
and you will also have to add the async keyword to your top function that wraps your code, but if this is a website you'll need to use babel for this to work in all browsers.
another take is using the callback technique but you will have to do some rewrite, but here is a start:
fetch('https://jsonplaceholder.typicode.com/photos')
.then(response => response.json())
.then(data => {
const currentPhotos = data.slice(firstPage, lastPage);
const renderPhotos = currentPhotos.map((photo) => {
return <tr key={photo.id}>
<td className="number">{photo.title}</td>
</tr>
});
});
fetch returns a Promise, so if you want to use slice method, you should use it inside the last .then(), but it would be better if you fetch your data in componentDidMount, save your data in React state, and after that use in render method;
for example, your code should look like:
componentDidMount() {
fetch('https://jsonplaceholder.typicode.com/photos')
.then(response => {
const data = response.json();
this.setState({
data: data,
});
);
}
render() {
const { currentPage, usersPerPage, data } = this.state;
const currentPhotos = data.slice(firstPage, lastPage);
const renderPhotos = currentPhotos.map((photo) => (
<tr key={photo.id}>
<td className="number">{photo.title}</td>
</tr>
);
const numbers = [];
for (let i = 1; i <= Math.ceil(data.length / usersPerPage); i++) {
numbers.push(i);
}
const renderPagination = numbers.map(number => {
return (
<li className="controls" key={number} id={number} onClick={this.handlePages}>
{number}
</li>
);
});
}
I'm new with React and i'm trying to render a json from a websocket.
Right now i'm able to get the json from the websocket using this :
componentWillMount() {
this.ws = new WebSocket('ws://10.77.0.79:1234')
this.ws.onmessage = e => this.setState({data: Object.values((e.data))})
this.ws.onerror = e => this.setState({ error: 'WebSocket error' })
this.ws.onclose = e => !e.wasClean && this.setState({ error: `WebSocket error: ${e.code} ${e.reason}` })
}
And then i need to map this json, right now i'm using this:
render() {
// this is my json from websocket
var json2 = {"Auth":{"status":"true","user":"gesplan","pass":"root"}}
var arr = [];
Object.keys(json2).forEach(function(key) {
arr.push(json2[key]);
});
return <ul>{arr.map(item => <MyAppChild key={item.status} label={item.status} value={item.user} pass={item.pass} />)} {this.state.data} </ul>;
}
}
class MyAppChild extends React.Component {
render() {
return <li>{this.props.label + " - " + this.props.value + this.props.pass } </li>;
}
}
With this i can render the values of the var json2.
How can i do it with my this.state.data? when i change json2 for this.state.data it return a null, but how can the state be null if i am rendering it normally?
Set your initial state to an empty array first. Append data when new data comes in:
constructor() {
this.state = {
data: []
}
}
componentWillMount() {
this.ws = new WebSocket('ws://10.77.0.79:1234')
this.ws.onmessage = e => this.setState({
data: [].concat(this.state.data, JSON.parse(e.data).Auth)
})
this.ws.onerror = e => this.setState({ error: 'WebSocket error' })
this.ws.onclose = e => !e.wasClean && this.setState({ error: `WebSocket error: ${e.code} ${e.reason}` })
}
render() {
return (
<ul>
{this.state.data.map(item =>
<MyAppChild key={item.status} label={item.status} value={item.user} pass={item.pass} />)
}
</ul>
);
}