React JSON API gives this.state.map not a function error - javascript

Hey I have been trying to figure out a fix for this for a while, I've searched here and all over but I've found nothing.
I have an API, it contains nested arrays, and is given through JSON.
I am able to get the contents inside the JSON to display when I use the console.log, but when I try to map the arrays, I constantly get errors stating that there's an issue with the .map function.
From what I have seen, it usually happens because it doesn't work with a string, but it's not being applied to a string from what I can tell...
There's a lot of data in the API, but I'm sure once I know how to get just one, eg the date, to display then I'll be fine with the rest.
Here is the code
export default class App extends React.Component {
constructor() {
super();
this.state = {
myItem: []
};
}
componentDidMount() {
this.getItems();
}
getItems () {
fetch('MYAPIGOESHERE')
.then(results => results.json())
//THIS BELOW WORKS
.then(results => console.log(results.date, results.location));
//THIS BELOW AND THE RENDER DOES NOT
.then(myItem => this.setState({myItem}))
}
render() {
return (
<div>
{this.state.myItem.map (myItem =>
<div> {myItem.date} </div> )}
</div>
)
})
}
}
Thank you!
{"date":"2018-09-16T11:22:00.000Z","location":"Cardiff City Stadium","teams":[{"name":"Cardiff City","homeTeam":true,"formation":"4-4-2","players":[{"playerId":"5afc0b73b481e9b536c4727b","position":"GK"},{"playerId":"5afc1377b481e9b536c4727c","position":"RB"},{"playerId":"5afc188bb481e9b536c47299","position":"CB"},{"playerId":"5afc188ab481e9b536c47297","position":"CB"},{"playerId":"5afc1872b481e9b536c4727e","position":"LB"},{"playerId":"5afc1873b481e9b536c4727f","position":"RM"},{"playerId":"5afc1874b481e9b536c47280","position":"CM"},{"playerId":"5afc1876b481e9b536c47281","position":"CM"},{"playerId":"5afc1876b481e9b536c47282","position":"LM"},{"playerId":"5afc1876b481e9b536c47283","position":"FW"},{"playerId":"5afc1877b481e9b536c47284","position":"FW"}]},{"name":"Swansea City","homeTeam":false,"formation":"4-3-3","players":[{"playerId":"5afc187ab481e9b536c4728a","position":"GK"},{"playerId":"5afc1878b481e9b536c47286","position":"RB"},{"playerId":"5afc1879b481e9b536c47289","position":"CB"},{"playerId":"5afc187ab481e9b536c4728b","position":"CB"},{"playerId":"5afc187bb481e9b536c4728c","position":"LB"},{"playerId":"5afc1879b481e9b536c47288","position":"RM"},{"playerId":"5afc1878b481e9b536c47287","position":"CM"},{"playerId":"5afc187bb481e9b536c4728d","position":"LM"},{"playerId":"5afc187cb481e9b536c47290","position":"FW"},{"playerId":"5afc187db481e9b536c47291","position":"FW"},{"playerId":"5afc187db481e9b536c47292","position":"FW"}]}]}

You can't map over this.state.myItem because it's an object.
You could do:
<div>{this.state.myItem.date}</div>
If you have an array of objects, you can do:
<div>{this.state.myItems.map(e => <div>{e.date}</div>)}</div>
for example.
If you have an object with an array in it, you can do:
const { teams } = this.state.myItem;
<div>{teams.map(t => <div>{t}</div>)}</div>
The data you have is like this: Object --> Array --> Object, so you can combine the above to display the data you want.

Try wrapping setState in braces:
.then(myItem => {
this.setState({myItem})
})
Map function works with arrays, you seem to have a single object. Try this:
return (
<div> {this.state.myItem.date} </div>
)
and remove the space between map and the opening parentheses.

Related

objects are not valid as a React child. Use array instead [duplicate]

In my component's render function I have:
render() {
const items = ['EN', 'IT', 'FR', 'GR', 'RU'].map((item) => {
return (<li onClick={this.onItemClick.bind(this, item)} key={item}>{item}</li>);
});
return (
<div>
...
<ul>
{items}
</ul>
...
</div>
);
}
everything renders fine, however when clicking the <li> element I receive the following error:
Uncaught Error: Invariant Violation: Objects are not valid as a React
child (found: object with keys {dispatchConfig, dispatchMarker,
nativeEvent, target, currentTarget, type, eventPhase, bubbles,
cancelable, timeStamp, defaultPrevented, isTrusted, view, detail,
screenX, screenY, clientX, clientY, ctrlKey, shiftKey, altKey,
metaKey, getModifierState, button, buttons, relatedTarget, pageX,
pageY, isDefaultPrevented, isPropagationStopped, _dispatchListeners,
_dispatchIDs}). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from
the React add-ons. Check the render method of Welcome.
If I change to this.onItemClick.bind(this, item) to (e) => onItemClick(e, item) inside the map function everything works as expected.
If someone could explain what I am doing wrong and explain why do I get this error, would be great
UPDATE 1:
onItemClick function is as follows and removing this.setState results in error disappearing.
onItemClick(e, item) {
this.setState({
lang: item,
});
}
But I cannot remove this line as I need to update state of this component
I was having this error and it turned out to be that I was unintentionally including an Object in my JSX code that I had expected to be a string value:
return (
<BreadcrumbItem href={routeString}>
{breadcrumbElement}
</BreadcrumbItem>
)
breadcrumbElement used to be a string but due to a refactor had become an Object. Unfortunately, React's error message didn't do a good job in pointing me to the line where the problem existed. I had to follow my stack trace all the way back up until I recognized the "props" being passed into a component and then I found the offending code.
You'll need to either reference a property of the object that is a string value or convert the Object to a string representation that is desirable. One option might be JSON.stringify if you actually want to see the contents of the Object.
So I got this error when trying to display the createdAt property which is a Date object. If you concatenate .toString() on the end like this, it will do the conversion and eliminate the error. Just posting this as a possible answer in case anyone else ran into the same problem:
{this.props.task.createdAt.toString()}
I just got the same error but due to a different mistake: I used double braces like:
{{count}}
to insert the value of count instead of the correct:
{count}
which the compiler presumably turned into {{count: count}}, i.e. trying to insert an Object as a React child.
Just thought I would add to this as I had the same problem today, turns out that it was because I was returning just the function, when I wrapped it in a <div> tag it started working, as below
renderGallery() {
const gallerySection = galleries.map((gallery, i) => {
return (
<div>
...
</div>
);
});
return (
{gallerySection}
);
}
The above caused the error. I fixed the problem by changing the return() section to:
return (
<div>
{gallerySection}
</div>
);
...or simply:
return gallerySection
React child(singular) should be type of primitive data type not object or it could be JSX tag(which is not in our case). Use Proptypes package in development to make sure validation happens.
Just a quick code snippet(JSX) comparision to represent you with idea :
Error : With object being passed into child
<div>
{/* item is object with user's name and its other details on it */}
{items.map((item, index) => {
return <div key={index}>
--item object invalid as react child--->>>{item}</div>;
})}
</div>
Without error : With object's property(which should be primitive, i.e. a string value or integer value) being passed into child.
<div>
{/* item is object with user's name and its other details on it */}
{items.map((item, index) => {
return <div key={index}>
--note the name property is primitive--->{item.name}</div>;
})}
</div>
TLDR; (From the source below) : Make sure all of the items you're rendering in JSX are primitives and not objects when using React. This error usually happens because a function involved in dispatching an event has been given an unexpected object type (i.e passing an object when you should be passing a string) or part of the JSX in your component is not referencing a primitive (i.e. this.props vs this.props.name).
Source - codingbismuth.com
Mine had to do with forgetting the curly braces around props being sent to a presentational component:
Before:
const TypeAheadInput = (name, options, onChange, value, error) => {
After
const TypeAheadInput = ({name, options, onChange, value, error}) => {
I too was getting this "Objects are not valid as a React child" error and for me the cause was due to calling an asynchronous function in my JSX. See below.
class App extends React.Component {
showHello = async () => {
const response = await someAPI.get("/api/endpoint");
// Even with response ignored in JSX below, this JSX is not immediately returned,
// causing "Objects are not valid as a React child" error.
return (<div>Hello!</div>);
}
render() {
return (
<div>
{this.showHello()}
</div>
);
}
}
What I learned is that asynchronous rendering is not supported in React. The React team is working on a solution as documented here.
Mine had to do with unnecessarily putting curly braces around a variable holding a HTML element inside the return statement of the render() function. This made React treat it as an object rather than an element.
render() {
let element = (
<div className="some-class">
<span>Some text</span>
</div>
);
return (
{element}
)
}
Once I removed the curly braces from the element, the error was gone, and the element was rendered correctly.
For anybody using Firebase with Android, this only breaks Android. My iOS emulation ignores it.
And as posted by Apoorv Bankey above.
Anything above Firebase V5.0.3, for Android, atm is a bust. Fix:
npm i --save firebase#5.0.3
Confirmed numerous times here
https://github.com/firebase/firebase-js-sdk/issues/871
I also have the same problem but my mistake is so stupid. I was trying to access object directly.
class App extends Component {
state = {
name:'xyz',
age:10
}
render() {
return (
<div className="App">
// this is what I am using which gives the error
<p>I am inside the {state}.</p>
//Correct Way is
<p>I am inside the {this.state.name}.</p>
</div>
);
}
}
Typically this pops up because you don't destructure properly. Take this code for example:
const Button = text => <button>{text}</button>
const SomeForm = () => (
<Button text="Save" />
)
We're declaring it with the = text => param. But really, React is expecting this to be an all-encompassing props object.
So we should really be doing something like this:
const Button = props => <button>{props.text}</button>
const SomeForm = () => (
<Button text="Save" />
)
Notice the difference? The props param here could be named anything (props is just the convention that matches the nomenclature), React is just expecting an object with keys and vals.
With object destructuring you can do, and will frequently see, something like this:
const Button = ({ text }) => <button>{text}</button>
const SomeForm = () => (
<Button text="Save" />
)
...which works.
Chances are, anyone stumbling upon this just accidentally declared their component's props param without destructuring.
Just remove the curly braces in the return statement.
Before:
render() {
var rows = this.props.products.map(product => <tr key={product.id}><td>{product.name}</td><td>{product.price}</td></tr>);
return {rows}; // unnecessary
}
After:
render() {
var rows = this.props.products.map(product => <tr key={product.id}><td>{product.name}</td><td>{product.price}</td></tr>);
return rows; // add this
}
I had the same problem because I didn't put the props in the curly braces.
export default function Hero(children, hero ) {
return (
<header className={hero}>
{children}
</header>
);
}
So if your code is similar to the above one then you will get this error.
To resolve this just put curly braces around the props.
export default function Hero({ children, hero }) {
return (
<header className={hero}>
{children}
</header>
);
}
I got the same error, I changed this
export default withAlert(Alerts)
to this
export default withAlert()(Alerts).
In older versions the former code was ok , but in later versions it throws an error. So use the later code to avoid the errror.
This was my code:
class App extends Component {
constructor(props){
super(props)
this.state = {
value: null,
getDatacall : null
}
this.getData = this.getData.bind(this)
}
getData() {
// if (this.state.getDatacall === false) {
sleep(4000)
returnData("what is the time").then(value => this.setState({value, getDatacall:true}))
// }
}
componentDidMount() {
sleep(4000)
this.getData()
}
render() {
this.getData()
sleep(4000)
console.log(this.state.value)
return (
<p> { this.state.value } </p>
)
}
}
and I was running into this error. I had to change it to
render() {
this.getData()
sleep(4000)
console.log(this.state.value)
return (
<p> { JSON.stringify(this.state.value) } </p>
)
}
Hope this helps someone!
If for some reason you imported firebase. Then try running npm i --save firebase#5.0.3. This is because firebase break react-native, so running this will fix it.
In my case it was i forgot to return a html element frm the render function and i was returning an object . What i did was i just wrapped the {items} with a html element - a simple div like below
<ul>{items}</ul>
Just remove the async keyword in the component.
const Register = () => {
No issues after this.
In my case, I added a async to my child function component and encountered this error. Don't use async with child component.
I got this error any time I was calling async on a renderItem function in my FlatList.
I had to create a new function to set my Firestore collection to my state before calling said state data inside my FlatList.
My case is quite common when using reduce but it was not shared here so I posted it.
Normally, if your array looks like this:
[{ value: 1}, {value: 2}]
And you want to render the sum of value in this array. JSX code looks like this
<div>{array.reduce((acc, curr) => acc.value + curr.value)}</div>
The problem happens when your array has only one item, eg: [{value: 1}].
(Typically, this happens when your array is the response from server so you can not guarantee numbers of items in that array)
The reduce function returns the element itself when array has only one element, in this case it is {value: 1} (an object), it causes the Invariant Violation: Objects are not valid as a React child error.
You were just using the keys of object, instead of the whole object!
More details can be found here: https://github.com/gildata/RAIO/issues/48
import React, { Component } from 'react';
import PropTypes from 'prop-types';
class SCT extends Component {
constructor(props, context) {
super(props, context);
this.state = {
data: this.props.data,
new_data: {}
};
}
componentDidMount() {
let new_data = this.state.data;
console.log(`new_data`, new_data);
this.setState(
{
new_data: Object.assign({}, new_data)
}
)
}
render() {
return (
<div>
this.state.data = {JSON.stringify(this.state.data)}
<hr/>
<div style={{color: 'red'}}>
{this.state.new_data.name}<br />
{this.state.new_data.description}<br />
{this.state.new_data.dependtables}<br />
</div>
</div>
);
}
}
SCT.propTypes = {
test: PropTypes.string,
data: PropTypes.object.isRequired
};
export {SCT};
export default SCT;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
If you are using Firebase and seeing this error, it's worth to check if you're importing it right. As of version 5.0.4 you have to import it like this:
import firebase from '#firebase/app'
import '#firebase/auth';
import '#firebase/database';
import '#firebase/storage';
Yes, I know. I lost 45 minutes on this, too.
I just put myself through a really silly version of this error, which I may as well share here for posterity.
I had some JSX like this:
...
{
...
<Foo />
...
}
...
I needed to comment this out to debug something. I used the keyboard shortcut in my IDE, which resulted in this:
...
{
...
{ /* <Foo /> */ }
...
}
...
Which is, of course, invalid -- objects are not valid as react children!
I'd like to add another solution to this list.
Specs:
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-redux": "^5.0.6",
"react-scripts": "^1.0.17",
"redux": "^3.7.2"
I encountered the same error:
Uncaught Error: Objects are not valid as a React child (found: object
with keys {XXXXX}). If you meant to render a collection of children,
use an array instead.
This was my code:
let payload = {
guess: this.userInput.value
};
this.props.dispatch(checkAnswer(payload));
Solution:
// let payload = {
// guess: this.userInput.value
// };
this.props.dispatch(checkAnswer(this.userInput.value));
The problem was occurring because the payload was sending the item as an object. When I removed the payload variable and put the userInput value into the dispatch everything started working as expected.
If in case your using Firebase any of the files within your project.
Then just place that import firebase statement at the end!!
I know this sounds crazy but try it!!
I have the same issue, in my case,
I update the redux state, and new data parameters did not match old parameters, So when I want to access some parameters it through this Error,
Maybe this experience help someone
My issue was simple when i faced the following error:
objects are not valid as a react child (found object with keys {...}
was just that I was passing an object with keys specified in the error while trying to render the object directly in a component using {object} expecting it to be a string
object: {
key1: "key1",
key2: "key2"
}
while rendering on a React Component, I used something like below
render() {
return this.props.object;
}
but it should have been
render() {
return this.props.object.key1;
}
If using stateless components, follow this kind of format:
const Header = ({pageTitle}) => (
<h1>{pageTitle}</h1>
);
export {Header};
This seemed to work for me
Something like this has just happened to me...
I wrote:
{response.isDisplayOptions &&
{element}
}
Placing it inside a div fixed it:
{response.isDisplayOptions &&
<div>
{element}
</div>
}

Fetch and array of objects from a database and displaying it with react

I was trying to fetch an array of objects when I encounter this problem. Sorry for my messy code, I'm a beginner.
export class App extends Component {
state ={
character:[]
}
componentDidMount(){
fetch('https://swapi.dev/api/people/').then(data => data.json()).then(res =>{
this.setState(() =>{
const ar = res.results
return {
character: ar
}
})
})
}
render() {
return (
<div>
test
{console.log(this.state.character[0])}
</div>
)
}
}
That code works fine for me at first until I changed the console log to {console.log(this.state.character[0].name)} it says "cannot read property of an undefined" even though the first line displays the object perfectly
Your App component fetches the data in componentDidMount life cycle method which will execute after the first mount. {console.log(this.state.character[0].name)} shows error "cannot read property of undefined because when the component mounts for first time, the data is not available yet, which means this.state.character is still an empty array. So when try to access this.state.character[0].name, its like saying give me the value of undefined.name which will give you an error because name property does not exist on undefined. To fix this issue you can check if character.length in a conditional and then try to access .name.
Example
render() {
return (
<div>
test
{this.state.character.length && <p>{this.state.character[0].name}</p>}
</div>
)
}
Fetch is asynchronous so you will take some time to get the result but before that your jsx is called already. So it is good to use conditional jsx. Please check the complete example as below where I shown all the name of character array under li element.
export class App extends React.Component {
state = {
character: []
};
componentDidMount() {
fetch('https://swapi.dev/api/people/').then(data => data.json()).then(res => {
this.setState(() => {
const ar = res.results;
return {
character: ar
}
})
})
}
render() {
return (
<div>
test
{
this.state.character && this.state.character.length && this.state.character.map((item, index) => {
return <li key={index}>{item.name}</li>
})
}
</div>
)
}
}
export default App;
So that will not work. Data is not there yet. There are bunch of ways to workaround it. Most simple one is to have object structure predefined in the state object, which is not very dynamic. Otherwise simple .length + if + else will do the job.

React State Appears but Only first array is accessible

I need to loop through an array that is nested within an array in my React State. I see the state is populated with both arrays in Dev Tools, also, when I loop through the parent array with Object.keys(this.state.products).map I get all of the values. The issue is when I try to loop over the child array, or pull any value from the child array, such as this.state.products[0][3] I get Undefined errors.
Whats more, is when I console.log this.state.products[0][3] in ComponenetDidUpdate I get the value, so it's like React is setting the state but not all the way?
const { Component } = React;
class App extends Component {
state = { products: [] };
componentDidMount() {
this.apiSearch();
}
apiSearch = () => {
// api call is made here
const API = `http://localhost:5000/products`;
fetch(API)
// api response log
// .then(response => console.log(response))
.then(response => response.json())
.then(data => {
this.setState({ products: data }, () =>
this.setState({ products: data })
);
})
.catch(err => {
console.log(err);
});
};
render() {
return (
<div className="App">
{<div>{typeof this.state.products[0]}</div>}
{/* issue is here !!!! */}
{<div>{typeof this.state.products[0][3]}</div>}
{/* issue is here !!!! */}
{this.state.products.forEach(function(element) {
console.log(element);
})}
<br></br>
Listings:
{Object.keys(this.state.products).map((keyName, i) => (
<li className="listingItem_Parent" key={i}>
<span className="listingItem">
{i} Name: {this.state.products[keyName]}
</span>
</li>
))}
<br></br>
</div>
);
}
}
ReactDOM.render(<App/>, document.getElementById("root"));
<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>
I need to iterate through the child array in "products" which is set in state and generate a nice list of them like with map in the first array.
Your component's render is called before the fetch occurs. At that point, your state just contains { products: [] }, so naturally this.state.products[0][3] fails because this.state.products[0] is undefined at that point. You need to either initialize your state such that this.state.products[0][3] is meaningful, or update render so that it doesn't fail when there is nothing in this.state.products.
There are a fair number of possibilities. First, check the console output, it is likely you're getting a warning explaining what's going on.
First, check that the state is really an array and not an error or some other object.
Secondly, you are explicitly checking something out of bounds in the initial state (the other answer just posted suggested this).
Third, make sure you use an key/ID when iterating over the list, it might not work without it (it should generate a warning).
//something like this
{ this.state.products.map( p => {
return (<span key={p.id}>{p.name /*whatever*/}</span>)
} )
Basically make sure that render method works with any and all data, right now there are no checks in place to validate the source so you might have something unexpected crashing your application. The hard coded index out of bounds is highly suspect.
componentDidMount() runs after the first render. So, the fetch is not even done by the time the first return is executed, which means this.state.products is still an empty array.
And you are performing actions on an empty array at this moment. Which is why
this.state.products[0][3] will fail.
At this moment:
this.state.products =[]
this.state.products[0] = undefined
this.state.products[0][3] -> error since you are checking for [3] of undefined.
You need to check if the array is empty and then perform actions based only when it's not.

Accessing data from Axios GET request

I'm having trouble accessing data from an Axios GET request. I'd like to be able to iterate through all of the data I get and create a table that displays the username, avatar, and score for each user. The only way I'm able to currently render a single username is with the following code:
this.setState({name: res.data[0].username});
But the above code only gives me access to the first object in the URL I use in the GET request. If I use this code:
this.setState({name: JSON.stringify(res.data)});
I'm able to render the entire object as a string. So that makes me think I need to update my render method, but I'm not sure how.
What steps should I take so that I can map over the state that I'm setting and render each user's data in a table or list?
class LeaderBoard extends React.Component {
constructor(props) {
super(props)
this.state = {
name: []
}
}
componentDidMount(){
axios.get('https://fcctop100.herokuapp.com/api/fccusers/top/recent').then(res =>
{
this.setState({name: res.data[0].username});
});
}
render () {
return (
<div>
<h1>{this.state.name}</h1>
</div>
)
}
}
ReactDOM.render(
<LeaderBoard/>, document.getElementById("app"));
You're on the right track, you're just missing a few key pieces.
Step 1: Add the entire array to your state
I'm not sure of the exact structure of your data, but you likely want to do this
componentDidMount(){
axios.get('https://fcctop100.herokuapp.com/api/fccusers/top/recent').then(res =>
{
this.setState({data: res.data});
});
}
Now you have all the data you want to work with in your state, ready to be iterated over.
Step 2: Use .map() to create the JSX elements you want
This code here:
render () {
return (
<div>
<h1>{this.state.name}</h1>
</div>
)
}
}
The big fault here is that it will only ever render one thing, because, well, that's all there is. What you want to do is .map() through and create a bunch of names from your data, right?
That would look more like this.
render () {
const namesToRender = this.state.data.map(val => {
return (
<h1>val.username</h1>
)
})
return (
<div>
{namesToRender}
</div>
)
}
}
All this is saying is "Go through that data and give me the name of each person and wrap it in some <h1> tags and spit that out".

Rendering an array of objects React

Good afternoon,
I am trying to display data that is provided to my application by an instance of MongoDB before the initial render. I have yet been successful in doing so either running into errors or warnings.
This is the part of the render method I am working with.
<div className="right-column">
<div className="pipeline">
{this.props.tournamentList.map((x,i) => {
return <li key={i}>{x.name}</li>
})}
</div>
</div>
this.props.tournamentList has a value of an array of objects like so:
tournamentList:
Array[15]
0:
{…}
1:
{…}
2:
{…} ...
This list comes to my application through the componentWillMount lifecycle method, so before the initial render. To me I should be able to iterate through the array and make a dynamically generated list of tournaments provided by my database.
Yet with the code I provided I am getting this warning:
Uncaught (in promise) Error: Objects are not valid as a React child (found: object with keys {prelims, outRounds, notes}). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method ofBuildTournament.
I tried this approach, creating called displayTournaments and calling it inside the div with the class of "pipeline" but nothing happens, no errors no render:
displayTournaments(){
const { tournamentList } = this.props;
tournamentList.map((x,i) => {
return <li key={i}>{x.name}</li>
})
}
Clearly I am doing something wrong but I don't know what. Is this an instance where I should be using keyed fragments as suggested by the error message? Would anyone smarter than myself be willing to lend some insight?
Cheers.
Update:
Sorry, I misunderstood your question. Kyle is correct with the loading state.
In addition, using a library like lodash will allow you to map over objects in a more natural manner. The native javascript map method doesn't handle objects all that well.
https://www.npmjs.com/package/lodash
you use it much the same way. just
import _ from lodash
then
_.map(objectToMap, (x) => <Component key={x}>{x.thing}</Component>)
Here would be a simple solution that would have a loading state, error state, and success state.
The first thing to note is you will need to use Object.keys() to your object in order to map over the array of keys since you cannot map plain objects. You should also note that the map will return the key of each object so in order to target key values pairs you will need to use a syntax like this tournaments[key].name rather than just doing tournament.name as you are targeting an object with in an object and then grabbing the value.
Let me know if you need any more help with this
import React from 'react'
import Loader from '../Loader'
const resultList = ({ tournaments, isFetching = true }) => (
<div>
{
isFetching
? <div>
<Loader /><br />
<span>Loading…</span>
</div>
: <div>
{
Object.keys(tournaments).length
? <div>
{
tournaments.map((key) => (
<section id={tournaments[key].id} key={key}>
<p>{tournaments[key].name}</p>
</section>
))
}
</div>
: <div>
<p>There are no tournaments....</p>
</div>
}
</div>
}
</div>
);
export default resultList
You are going to need to have a loading state if you get your data in the componentWillMount or componentDidMount lifecycle hooks. The below example will illustrate how this is done.
class ComponentThatGetsAsyncData extends PureComponent {
constructor( props ) {
super( props );
this.state = {
tournamentList: [ ]
}
}
componentDidMount() {
// use any http library you choose
axios.get( "/some_url" )
.then( ( res ) => {
// this will trigger a re-render
this.setState({
tournamentList: res.data
});
})
.catch( ( err ) => {
// handle errors
});
}
render() {
const { tournamentList } = this.state;
// i'd use something other than index for key
// on your initial render your async data will not be available
// so you give a loading indicator and when your http call
// completes it will update state, triggering a re-render
return (
{
tournamentList ?
tournamentList.map((x,i) => {
return <li key={i}>{x.name}</li>
}) :
<div className="loading">Loading...</div>
}
);
}
}

Categories

Resources