So, I have the exact same problem as our friend here :
How to render properties of objects in React?
The below (upvoted) solution by Nahush Farkande :
render() {
let user = this.props.user || {};
....
{user.email}
....
}
works for me... if user is an object. However, in my specific case, the data I fetch and want to render is an array of objects.
So, I return something like that :
<ul>
{
user.map( (el, idx) => {
return (
<li key = {idx}>
<div className="panel-body clearfix">
{el.title}
</div>
</li>
)
})
}
</ul>
That doesn't work. I get an error message that tells me that user.map is not a function (before [HMR] connected).
I expected that once the API fetches the user array of objects, the component would re-render and then the component would show the list of titles from each object of the user array (after [HMR] connected).
If your user
(I recommend to rename to users
) is an array, then you cannot use {}
as the default. You should use []
as the default value:
const user = this.props.user || []
or, you can use a completely different branch to handle the loading case:
if (!this.props.user) {
return (
<div> ... my loading placeholder ... </div>
);
}
You already have correct answer but just wanted to give a running example.
Initialize your data in your state with the default values e.g
in case of object -> {}
in case or array -> []
Obviously in each case your rendering logic should be different e.g in case of array you need the map
to loop over array and generate jsx element
.
So when ever your component receives the updated data ( either it can be empty data or complete data) either via api call or via prop changes use the appropriate life cycle method such as componentWillReceiveProps
or componentDidMount
to get the latest data and again set the state with latest data.
For example when data is received via api call ->
constructor() {
this.state = {
data : []
}
}
componentDidMount()
{
this.getFunction();
}
getFunction = () => {
this.ApiCall()
.then(
function(data){
console.log(data);
// set the state here
this.setState({data:data});
},
function(error){
console.log(error);
}
);
}
So at the time of initial render your data will be either empty object or empty array and you will call appropriate rendering method for that accordingly.
class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
data : []
}
}
componentWillMount() {
this.setState({ data : this.props.dp });
}
renderFromProps() {
return this.state.data
.map((dpElem) =>
<h3>{dpElem.name}</h3>
);
}
render() {
return (
<div>
<h1> Rendering Array data </h1>
<hr/>
{ this.renderFromProps()}
</div>
);
}
}
const dynamicProps = [{ name:"Test1", type:"String", value:"Hi1" },
{ name:"Test2", type:"String", value:"Hi2" },
{ name:"Test3", type:"String", value:"Hi3" }
];
ReactDOM.render(
<Test dp={dynamicProps} />,
document.getElementById('root')
);
<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>
<div id="root">
</div>