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)
})
}
Related
I have a react JSX component that makes an api call to the backend and fetches the data I require. This data is currently inside a react-select tag which allows me to display all the options inside a dropdown. I'm trying now to use this dropdown to render the selection using charts, specifically react-chartjs-2. I've been trying for quite a while but I honestly am at my wits end.
Here's what the api call with the select looks like:
export default class ------ extends component{
constructor(props, context) {
super(props, context);
this.state = {
selectedOption: {},
};
}
fetchData = (inputValue, callback) => {
setTimeout(() => {
fetch(
"api" +
inputValue,
{
method: "GET",
}
)
.then((resp) => {
return resp.json();
})
.then((data) => {
const tempArray = [];
if (data) {
if (data.length) {
data.forEach((element) => {
tempArray.push({
label: `${element.campo}`,
value: element.valor,
});
});
} else {
tempArray.push({
label: `${data.campo}`,
value: data.valor,
});
}
}
callback(tempArray);
})
.catch((error) => {
console.log(error, "error");
});
}, 1000);
};
onSearchChange = (selectedOption) => {
if (selectedOption) {
this.setState({
selectedOption,
});
}
};
Here's the actual select element and the chart inside the return section
render(){
return(
<AsyncSelect
id="valx"
value={this.state.selectedOption}
loadOptions={this.fetchData}
placeholder="placehold"
onChange={(e) => {
this.onSearchChange(e);
}}
defaultOptions={true}
/>
<div class="charts">
<Bar
id="MyBarChart"
data={{}}
options={{}}
/>
<Pie
id="MyPieChart"
data={{}}
options={{}}
/>
</div>
I have a really long way to go when it comes to React, I'm sure the solution will turn out to be rather simple. Any and all help is welcome, and thanks in advance.
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 [];
}
}
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
I'm trying to implement a restaurant app where a user can add dishes to a menu. The menu will be displayed in a side bar. Dish information is provided through an API. I'm having issues with the API requests/promises. I'm storing a list of the dishes in DinnerModel. I'm making the requests to the API in DinnerModel.
When I add a dish to the menu by clicking the add button in IngredientsList, I get redirected to a screen that shows Sidebar. But in Sidebar, the dishes are NaN. The console.logs show that this.state.menu in Sidebar is actually a Promise, not an array. I'm having trouble understanding why this is and what to do about it.
Note that update in Sidebar is supposed to run modelInstance.getFullMenu() which returns an array. But instead, a promise is returned. Why? What can I do to fix this?
Here's my code:
Dinnermodel.js:
const DinnerModel = function () {
let numberOfGuests = 4;
let observers = [];
let selectedDishes = [];
// API Calls
this.getAllDishes = function (query, type) {
const url = 'https://spoonacular-recipe-food-nutrition-v1.p.mashape.com/recipes/search?query='+query+"&type="+type;
return fetch(url, httpOptions)
.then(processResponse)
.catch(handleError)
}
//function that returns a dish of specific ID
this.getDish = function (id) {
let url = "https://spoonacular-recipe-food-nutrition-v1.p.mashape.com/recipes/"+id+"/information";
return fetch(url, httpOptions)
.then(processResponse)
.catch(handleError)
}
// API Helper methods
const processResponse = function (response) {
if (response.ok) {
return response.json();
}
throw response;
}
this.addToMenu = function(id, type){
var newDish = this.getDish(id).then()
newDish.dishType = type;
selectedDishes.push(newDish);
notifyObservers();
}
//Returns all the dishes on the menu.
this.getFullMenu = function() {
return selectedDishes;
}
DishDetails.js:
class DishDetails extends Component {
constructor(props) {
super(props);
this.state = {
id: props.match.params.id,
status: "INITIAL",
type: props.match.params.type,
};
}
addToMenu (){
modelInstance.addToMenu(this.state.id, this.state.type);
this.props.history.push("/search/"+this.state.query+"/"+this.state.type);
}
componentDidMount = () => {
modelInstance.getDish(this.state.id)
.then(dish=> {
this.setState({
status:"LOADED",
ingredients: dish.extendedIngredients,
dishText: dish.winePairing.pairingText,
pricePerServing: dish.pricePerServing,
title: dish.title,
img: dish.image,
instructions: dish.instructions,
})
})
.catch(()=>{
this.setState({
status:"ERROR",
})
})
}
render() {
switch(this.state.status){
case "INITIAL":
return (
<p>Loading...</p>
);
case "ERROR":
return (
<p>An error has occurred, please refresh the page</p>
);
}
return (
<IngredientsList ingredients={this.state.ingredients} pricePerServing={this.state.pricePerServing} id={this.state.id} onButtonClick={() => this.addToMenu()}/>
<Sidebar />
);
}
}
export default withRouter(DishDetails);
Sidebar.js:
class Sidebar extends Component {
constructor(props) {
super(props)
// we put on state the properties we want to use and modify in the component
this.state = {
numberOfGuests: modelInstance.getNumberOfGuests(),
menu: modelInstance.getFullMenu(),
}
modelInstance.addObserver(this);
}
// this methods is called by React lifecycle when the
// component is actually shown to the user (mounted to DOM)
// that's a good place to setup model observer
componentDidMount() {
modelInstance.addObserver(this)
}
// this is called when component is removed from the DOM
// good place to remove observer
componentWillUnmount() {
modelInstance.removeObserver(this)
}
handleChangeGuests(event){
let noOfGuests = event.target.value;
modelInstance.setNumberOfGuests(noOfGuests);
}
// in our update function we modify the state which will
// cause the component to re-render
update() {
this.setState({
numberOfGuests: modelInstance.getNumberOfGuests(),
menu: modelInstance.getFullMenu(),
})
console.log("menu in Sidebar.js");
console.log(this.state.menu);
}
render() {
//console.log(this.state.menu);
let menu = this.state.menu.map((dish)=>
<div key={"menuitem-"+dish.id} className="menuitemwrapper">
<div className="menuitem">
<span className="dishname">{dish.title}</span>
<span className="dishprice">{dish.pricePerServing*modelInstance.getNumberOfGuests()}</span>
</div>
</div>
);
return (
<div id="sidebar-dishes">
{menu}
</div>
);
}
}
export default Sidebar;
IngredientsList.js:
class IngredientsList extends Component{
constructor(props){
super(props);
this.state = {
ingredients: props.ingredients,
pricePerServing: props.pricePerServing,
id: props.id,
noOfGuests: modelInstance.getNumberOfGuests(),
}
modelInstance.addObserver(this);
}
update(){
if(this._ismounted==true){
this.setState({
noOfGuests: modelInstance.getNumberOfGuests(),
});
}
}
componentDidMount(){
this._ismounted = true;
}
componentWillUnmount(){
this._ismounted = false;
}
render () {
return (
<button onClick={() => this.props.onButtonClick()} type="button" className="btn btn-default">Add to menu</button>
);
}
}
export default IngredientsList;
EDIT:
Changed DinneModel.addToMenu to:
this.addToMenu = function(id, type){
var newDish = this.getDish(id)
.then(()=>{
newDish.dishType = type;
selectedDishes.push(newDish);
notifyObservers();
});
}
I still get a promise logged in the console from the console.log in Sidebar.js, and NaN in the Sidebar render.
getDish is not in your code posted, but I assume that it returns a promise. And this.getDish(id).then() also returns a promise. That’s why selectedDishes array has promises in it.
this.addToMenu = function(id, type){
var newDish = this.getDish(id).then()
newDish.dishType = type;
selectedDishes.push(newDish);
notifyObservers();
}
To get actual newDish data, you need to use a callback function for the then.
this.addToMenu = function(id, type){
this.getDish(id).then(function (newDish) {
newDish.dishType = type;
selectedDishes.push(newDish);
notifyObservers();
});
}
A have a simply react/redux app. I Fetch data from API async but component not waiting for data and firing render.
class RestaurantList extends React.Component {
componentWillMount() {
this.props.getRestaurantList();
}
render() {
console.log("render");
let {translation} = store.getState().app;
//------------I NEED DATA ON THIS LET (restaurantList)
let {restaurantList} = this.props.restaurants;
return (
<div>
<TableContainer data={restaurantList}/>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
restaurants: state.restaurants
};
};
const mapDispatchToProps = (dispatch) => {
return {
getRestaurantList() {
dispatch(ACTIONS.getRestaurantList());
},
};
};
export default connect(mapStateToProps, mapDispatchToProps)(RestaurantList);
On my action i fetching data using axios :
export function getRestaurantList() {
console.log("action");
return dispatch => {
axios({
method: "GET",
url: URLS.BASE_URL + URLS.URL_RESTAURANT_LIST
}).then((response) => {
console.log(response);
dispatch({
type: CONST.GET_RESTAURANT_LIST,
payload: response.data
})
})
}
}
And my component fired method ComponenWillMount after that render () and next store which update store and set good data to my variable. Maybe u give me advice how to do that to have on my render my fetching data because now on my table I transfer undefined on start. Maybe you give me an example to using another framework like redux-saga or other.
You could try conditionally rendering your TableContainer component so the table will only be rendered once there is data available:
renderTable() {
let { restaurantList } = this.props.restaurants
if (restaurantList) {
return <TableContainer data={ restaurantList } />
} else {
return <div></div>
}
}
render() {
return (
<div>
{ this.renderTable() }
</div>
)
}