Automatic Columns in React-Table not working with JSON Arrays - javascript

I'm trying to dynamically generate a table from a fetch request. It's able to do it with JSON data without an array name, however when it does, it doesn't work. Here is the code: https://codesandbox.io/s/static-example-319q4
Here, the example works fine with the data that doesn't have an array name for the JSON data, however, when the other componentDidMount function is used, it doesn't work even though I specified the array name using "posts.launches".
class App extends React.Component {
constructor(props){
super(props);
this.state = {
posts: [],
value: '',
}
}
/*
Get response from an API endpoint and populates the
*/
componentDidMount() {
//const params = this.state.text
const url = "https://jsonplaceholder.typicode.com/posts";
fetch(url, {
method: "GET"
})
.then(response => response.json())
.then(posts => {
this.setState({ posts: posts });
});
}
/*
componentDidMount() {
//const params = this.state.text
const url = "https://hn.algolia.com/api/v1/search?query=redux";
fetch(url, {
method: "GET"
})
.then(response => response.json())
.then(posts => {
this.setState({ posts: posts.hits });
});
}
*/
getColumns() {
const getPostKeys = this.state.posts[0];
if (getPostKeys) {
const column =
this.state.posts &&
Object.keys(getPostKeys).map(key => {
return {
Header: key,
accessor: key
};
});
return column;
} else {
console.log("Error")
return [];
}
}
render() {
console.log(this.state.posts[0])
const columns = this.getColumns();
// console.log(JSON.stringify(this.state.initial_data));
return (
<div>
<ReactTable
data={this.state.posts}
columns={columns}
defaultPageSize={10}
className="-striped -highlight"
filterable
/>
<br />
</div>
);
}
}
ReactDOM.render( <
App / > ,
document.getElementById('app')
);
Any help would be great! Thanks!

Some of the data in your JSON is not consistent with the input that React Table expects its to be in a grid. Check for the condition in working example -
"_tags" && x !== "_highlightResult"
After removing these keys, I further baked the columns and its working fine. Please check the working example -
https://codesandbox.io/s/static-example-x2kjr
Code -
getColumns() {
const getPostKeys = this.state.posts[0];
if (getPostKeys) {
function isNotTagsOrHighlightKey(x) {
return x !== "_tags" && x !== "_highlightResult";
}
const getSanitizedColumns = Object.keys(getPostKeys).filter(
isNotTagsOrHighlightKey
);
const newColumn = getSanitizedColumns.map(key => {
return {
Header: key,
accessor: key
};
});
return newColumn;
} else {
console.log("Error");
return [];
}
}

Related

ComponentDidMount fires twice calling API

I am new to react.js so troubles caught me. I have small todo-list app connected with mockAPI. Application gets todo list data from API. As required, I call API inside componentDidMount() instead of constructor. However, API is called twice (only after page reloaded, not data manipulation as put\delete data to API). Any errors or warnings in console.
class App extends Component {
todoServ = new TodoServer();
constructor(props) {
super(props);
this.state = { data: [], maxId: 0 };
}
/*
code to add\delete\done todo item;
*/
findCurrentMaxId = (data) => {
const idList = [];
data.forEach(todo => {
idList.push(todo.id);
});
return Math.max(...idList);
}
updateTodoData = (data) => {
const maxId = this.findCurrentMaxId(data);
this.setState({ data, maxId });
}
getTodoData = () => {
this.todoServ
.getTodoList()
.then(this.updateTodoData)
.catch(this.errorTodoData);
}
componentDidMount() {
this.getTodoData();
}
render() {
return (
<div className="app">
<div className="content">
<AddTodoListItem onAddNewTodoItemData={this.onAddNewTodoItemData}/>
<TodoList
data={this.state.data}
onDoneTodoItemData={this.onDoneTodoItemData}
onDeleteTodoItemData={this.onDeleteTodoItemData} />
</div>
</div>
)
}
}
export default App;
Console:
This is the service fetches data.
class TodoService {
#url = `https://*secret*/todoslist/todo`;
async getResource(url) {
let res = await fetch(url);
if (!res.ok) {
throw new Error(`Could not fetch ${url}, status: ${res.status}`);
}
return await res.json();
}
async getTodoList() {
const res = await this.getResource(this.#url);
console.log('GET', res);
return res;
}
}
export default TodoService;
Thanks for the advices.

React - Iterating through state array with no result

I'm fetching JSON data from a local express server using mongoosejs to parse mongoDB queries. I'm getting a "title" and "id" from the server, to generate a sidebar of buttons.
But my issue is that I can't seem to iterate through the state array after fetching the data from the server
The GET request handler on the server:
exports.sidebar = (req, res) => {
Note.find({}, "_id title")
.then(notes => {
console.log(notes);
res.send(notes)
}).catch(err => {
return res.status(404).send({
message: err
})
})
}
My react component. in loadData(), i fetch the data from the API. and in loadSidebarElements() I try to iterate through the state array,
import React, {Component} from "react";
class Sidebar extends Component {
constructor(props) {
super(props);
this.state = {
titleList: [],
idList: []
}
this.loadData = this.loadData.bind(this);
this.loadSidebarElements = this.loadSidebarElements.bind(this);
}
componentDidMount() {
this.loadData();
}
loadData() {
let titles = [];
let ids = [];
const requestOptions = {
method: "GET",
headers: {"Content-Type" : "application/json"},
mode: "cors"
};
fetch("http://127.0.0.1:5000/notes/sidebar", requestOptions)
.then(response => response.json())
.then(data => {
data.map(item => {
titles[titles.length] = String(item.title);
ids[ids.length] = String(item._id);
})
})
this.setState({
titleList: titles,
idList: ids
})
}
loadSidebarElements(){
console.log(this.state.titleList);
this.state.titleList.map(item => {
console.log(item);
})
this.state.titleList.forEach(item => console.log(item));
Object.keys(this.state.titleList).map((key, index) => {
console.log(this.state.titleList[key]);
})
}
render() {
return (
<div className="sidebar" style={{display: "flex", flexDirection:"column", alignItems: "center"}}>
<h1>Sidebar:</h1>
{this.loadSidebarElements()}
</div>
)
}
}
export default Sidebar;
The console output in firefox:
Console log from firefox
I obviously get the data to the server, but I just can't seem to iterate through it...

Fetch the first element from the array with fake api 'myjson.com'

In the 'myjson.com' website, I created a url 'https://api.myjson.com/bins/17qwmf' which returns an array to me. How to get an element with 'id: 1', the first element from the array. I'm trying to do it this way: 'https://api.myjson.com/bins/17qwmf/1' but I'm getting an error.
From the documentation it looks like it can be done: http://myjson.com/api
Code here: stackblitz demo
class Items extends Component {
constructor (props) {
super(props);
this.state = {
items: []
}
}
componentDidMount() {
const id = 1;
axios.get
axios({
url: `https://api.myjson.com/bins/17qwmf/${id}`,
method: "GET"
})
.then(response => {
console.log(response.data);
this.setState({
items: response.data
});
})
.catch(error => {
console.log(error);
})
}
render () {
return (
<div >
</div>
)
}
}
if there is no a router for getting an element by it id, you have to filter got array
class Items extends Component {
constructor (props) {
super(props);
this.state = {
items: []
}
}
componentDidMount() {
const id = 1;
axios.get
axios({
url: `https://api.myjson.com/bins/17qwmf`,
method: "GET"
})
.then(response => {
console.log(response.data);
this.setState({
items: response.data.filter(item => item.id === id)[0] // you will get a first element of got array
});
})
.catch(error => {
console.log(error);
})
}
render () {
return (
<div >
</div>
)
}
}
Please check this `https://api.myjson.com/bins/17qwmf?id=${id} if you want to fetch only element with id that ur passed

Passing input value to react component

I'm trying to make a search functionality for my app. It works with API:
http://localhost:3005/products?q=[USER INPUT HERE]
and .JSON is returned from this. I already have a working component that I want to duplicate and use it for search results display. It looks like this:
class Item extends Component {
constructor(props) {
super(props);
this.state = {
output: {},
url: {}
}
}
componentDidMount() {
fetch(this.props.url)
.then(response => response.json())
.then(data => this.setState({ output: data }));
}
render() {
const { general = {name:"", description:""} } = this.state.output;
return (
<BoxTitle>{general.name}</BoxTitle>
);
}
}
working alright, rendered this way:
let ChoosePage = (i) => {
ReactDOM.unmountComponentAtNode(document.getElementById('items'))
let urls = [
'http://localhost:3005/products/774944',
'http://localhost:3005/products/774945',
...
'http://localhost:3005/products/738471'];
let urls_sliced = urls;
if (i === 0) {
urls_sliced = urls.slice(0, 4);
} else if (i === 1) {
urls_sliced = urls.slice(4, 8);
} else if (i === 2) {
urls_sliced = urls.slice(-2);
}
let show_items = () => {
ReactDOM.render(urls_sliced.map((url)=>{
return(
<Item url={url}/>
)
}), document.getElementById('items'));
}
show_items()}
this is my input field:
const search_box = (
<form>
<Icon>search</Icon>
<input placeholder={'Search...'}></input>
</form>
);
I'm looking for a way to pass value inputted by the user to function that will convert it to link and use for getting .JSON from API and then render components mapped with this data. Managed to make only this:
let url_s = 'http://localhost:3005/products?q=' + input;
let show_results = () => {
ReactDOM.render(urls_sliced.map((url)=>{
return(
<Item url={url_s}/>
)
}), document.getElementById('items'));
}
show_results()
Help is very appreciated here :)

map function value not displaying

In console.log the api fetched data are displaying but in browser itis
showing only white screen. In map function have to update the state function
import React, { Component } from 'react';;
import * as algoliasearch from "algoliasearch";
class App extends React.Component {
constructor() {
super();
this.state = {
data: { hits: [] }
}
// set data to string instead of an array
}
componentDidMount() {
this.getData();
}
getData() {
var client = algoliasearch('api-id', 'apikey');
var index = client.initIndex('');
//index.search({ query:""}, function(data){ console.log(data) })
//index.search({ query:""}, function(data){ console.log("DataRecib=ved. First check this") })
index.search({
query: "",
attributesToRetrieve: ['ItemRate', 'Color'],
hitsPerPage: 50,
},
function searchDone(error, data) {
console.log(data.hits)
});
}
render() {
return (
<div id="root">
{
this.state.data.hits.map(function (data, index) {
return
<h1>{this.setState.data.ItemRate}<br />{data.Color}</h1> >
})}
</div>
);
}
}
//render(<App />, document.getElementById('app'));
export default App;
Couple of mistakes -:
You just need to use this.state.data.ItemRate instead of this.setState.data.ItemRate.
You can get state inside .map using arrow functions ( . )=> { . }
Visit https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/
render() {
return (
<div id="root" >
{
this.state.data.hits.map((data,index) => {
return<h1>{this.state.data.ItemRate}<br />{data.Color}</h1>
}
Every this.setState triggers a render() call. If you setState inside render method, you go into an infinity loop.
You want to update this.state.data.hits inside getData() function, then you can display the data like so:
this.state.data.hits.map(data =>
<h1>{data.Color}</h1>
)
For example, if console.log(data.hits) logs out the correct data, then you can:
this.setState({
data: {
hits: data.hits
}
})
EDIT:
Using the code you provided, it should be like this:'
getData = () => {
var client = algoliasearch('A5WV4Z1P6I', '9bc843cb2d00100efcf398f4890e1905');
var index = client.initIndex('dev_twinning');
//index.search({ query:""}, function(data){ console.log(data) })
// index.search({ query:""}, function(data){ console.log("Data Recib=ved. First check this") })
index.search({
query: "",
attributesToRetrieve: ['ItemRate', 'Color'],
hitsPerPage: 50,
}, searchDone = (error, data) => {
this.setState({
data: {
hits: data.hits
}
})
console.log(data.hits)
})
}

Categories