Why this happens with React JS? - javascript

I am trying to fetch data using React JS and I am having the following error in my console:
Uncaught Error: Objects are not valid as a React child (found: object
with keys {productsList}). If you meant to render a collection of
children, use an array instead.
And here is my code:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';
class Products extends Component {
constructor(props) {
super(props);
this.state = {
products: []
};
}
//Lifecycle hook
componentDidMount () {
axios.get('/api/storageapp')
.then(response => {
console.log(response)
this.setState({
products: response.data,
})
})
}
render() {
const { products } = this.state;
const productsList = products.length ? (
products.map(product => {
return (
<div key={product.id}>
<div>{product.product_name}</div>
</div>
)
})
) : (
<div>No products were found.</div>
)
return (
{productsList}
);
}
}
export default Products;
if (document.getElementById('products')) {
ReactDOM.render(<Products />, document.getElementById('products'));
}
Any clue what's happening?

Because you're returning an object:
return (
{productsList}
);
You should be returning just productsList. Get rid of the object literal syntax around it.
return productsList;

Related

"TypeError: tasks.map is not a function"

I'm trying to call a dictionary from Django Rest Framework API to view on my frontend. Using Django backend & Reactjs frontend. Through some research looks like i'm getting this error due to the map() function only accepting arrays, while my API is returning a dictionary (I THINK SO).
How do I fix this? I'm new to javascript & apologies in advance for the messy code. Please see my App.js below:
App.js
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
todoList: [],
}
this.fetchTasks = this.fetchTasks.bind(this)
};
componentWillMount() {
this.fetchTasks()
}
fetchTasks() {
fetch('http://127.0.0.1:8000/api/api-overview')
.then(response => response.json())
.then(data =>
this.setState({
todoList: data
})
)
}
render() {
var tasks = this.state.todoList
return (
<div className="container">
{tasks.map(function (task, index) {
return (
<div className="center-column">
<div className="item-row">
<div key={index} className="centered">
<span>{task.bitcoin_symbol}</span>
</div>
</div>
</div>
)
})}
</div>
);
}
}
export default App;
API response:
You're fetching a single object, not an array. .map() is a method which run over iterables(arrays, strings, etc - objects, that can be iterated over) and creates a new output element from each input one. In react we mainly use it to convert an item to its JSX(react/html) representation. As you're working over a single object, you should access it directly:
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
bitcoinData = null
}
this.fetchBitcoinData = this.fetchBitcoinData.bind(this);
};
componentWillMount() {
this.fetchBitcoinData();
}
fetchBitcoinData() {
fetch('http://127.0.0.1:8000/api/api-overview')
.then(response => response.json())
.then(data =>
this.setState({
bitcoinData: data
});
);
}
getBitcoinRepresentation() {
var bitcoinData = this.state.fetchBitcoinData;
if (!bitcoinData) {
return <div>Loading...</div>;
}
else {
return (
<div className="container">
<div>{bitcoinData.bitcoin_symbol}</div>
<div>{bitcoinData.bitcoin_price}</div>
<div>{bitcoinData.bitcoin_dailychangeinprice}</div>
</div>
);
}
}
render() {
return getBitcoinRepresentation();
}
}
export default App;

how to render the state array in react component. the array is available in state but while rendering its showing undefined

I'm want to render data from firestore into my react component. I updated the global state array with firestore data and it's updating but when I'm going to render that array the array shows as undefined.
I have tried using redux and the same problem happened, now used reactn but same things are happening.
import React from "react";
import {setGlobal} from "reactn";
import ReactDOM from "react-dom";
import Apps from "./Apps";
setGlobal({ names:[],})
ReactDOM.render( <Apps/>, document.getElementById("root"))
ReactDOM.render(<Apps/>, document.getElementById("root"))`
-----App.js----------
import React from "reactn";
import db from "./firebase";
class Apps extends React.Component{
componentDidMount(){
db.collection("users").get().then((snapshot)=>{
snapshot.forEach((doc)=>{
const user= {name:doc.data().name,
weight:doc.data().weight,
id:doc.id}
this.global.names.push(user)
})
})
}
render(){
///this show the data in names array of state
console.log(this.global)
//// this show undefind (its having data)
console.log(this.global.names[0])
return(
///but while rendering its not showing anything
<div>{this.global.names.map((name)=>(
<h1>weight is {name.weight} </h1>
)
)}</div>
)
}
}
export default Apps;
instead of
this.global.names.push(user)
You have to use
this.setGlobal(names: names.push(user))
I think don't use global variable in react just do something like that
class Apps extends React.Component {
constructor(props) {
super(props)
this.state = {
names: [],
}
}
componentDidMount() {
let array = [];
db.collection("users").get()
.then((snapshot) => {
snapshot.forEach((doc) => {
const user = {
name: doc.data().name,
weight: doc.data().weight,
id: doc.id
}
array.push(user)
})
})
.then(() => {
this.setState({
names : array
})
})
}
render() {
///this show the data in names array of state
console.log(this.state.names)
//// this show undefind (its having data)
console.log(this.state.names[0])
return (
///but while rendering its not showing anything
<div>{this.state.names.map((name) => (
<h1>weight is {name.weight} </h1>
)
)}</div>
)
}
}
export default Apps;
Try this and tell me if it's works :)

higher order component can't see props

I'm using react with react-native and redux. The error comes to the component from the redux store. After that, i received: Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.
What is wrong with this? why hoc can't see the props?
My component:
import React, { Component } from 'react';
import withHandleError from './withHandleError';
class SendScreen extends Component {
render() {
const { error } = this.props;
return (
<div> Test </div>
)
}
};
const mapStateToProps = ({ppm}) => ({
error: ppm.error
})
export default withHandleError(connect(mapStateToProps)(SendScreen));
And HoC:
import React, { Component } from 'react';
import { ErrorScreen } from '../../ErrorScreen';
import { View } from 'react-native';
export default Cmp => {
return class extends Component {
render() {
const {error, ...rest } = this.props;
console.log(error) //// undefined....
if (error) {
return <ErrorScreen />
}
return <Cmp { ...rest } />
}
}
}
The order is which you call the HOCs matters when you want to access props supplied by one in another. Re-ordering your connect and withHandleError HOC will work
import React, { Component } from 'react';
import withHandleError from './withHandleError';
class SendScreen extends Component {
render() {
const { error } = this.props;
return (
<div> Test </div>
)
}
};
const mapStateToProps = ({ppm}) => ({
error: ppm.error
})
export default connect(mapStateToProps)(withHandleError(SendScreen));

react map is not a function

Yo guys, getting error 'contacts.map is not a function' not sure why is that ? just starting in react maybe missing something obvious. I'm getting the data when I console log all good.
code below:
import React, { Component } from 'react'
import axios from 'axios';
class Contacts extends Component {
constructor(){
super();
this.state = {
contacts: [],
}
}
componentDidMount(){
axios.get('url')
.then(response => {
this.setState({ contacts: response.data });
})
.catch(function (error) {
console.log(error);
})
}
render() {
const { contacts } = this.state
return(
<div>
{contacts.map(contact => (
<h1>contact.hello</h1>
))}
</div>
)
}
}
export default Contacts;
Apparently its an object not an array...
How can i render this object then?
It has one property for now but will have more later on: tried JSON.stringify(obj)
{hello: "test"}
The problem is that you set contacts to response.data, which evidently it's not an array.
componentDidMount fires after the component is mounted and tries to get the string 'url'. When state is updated, the component is redrawn and it gives the error.
Since the contacts is an object I would recommend you to do Object.keys and then .map on it so that you can get object keys and it’s values.
One more thing never forget to add unique key to the parent jsx element when you iterate array of data or an object like below.
<div>
{Object.keys(contacts).map((name, index) => (
<h1 key={'Key'+index}>{contacts[name]}</h1>
))}
</div>
From react docs:
Note:
These methods are considered legacy and you should avoid them in new code:
UNSAFE_componentWillMount()
When you want to wrap an object you can simply wrap it in brackets
class Contacts extends Component {
constructor() {
super();
this.state = {
contacts: [],
}
}
componentDidMount() {
axios.get('url')
.then(({ data }) => {
this.setState({ contacts: [data] });
})
.catch((error) => {
console.log(error);
});
}
render() {
const { contacts } = this.state;
return (
<div>
{contacts.map(contact => (
<h1 key={/* unique key */}>contact.hello</h1>
))}
</div>
);
}
}
Use async await to get the response before the component is mounted
import React, { Component } from 'react'
import axios from 'axios';
class Contacts extends Component {
constructor(){
super();
this.state = {
contacts: [],
}
}
async componentWillMount(){
const response = await axios.get('url')
this.setState({ contacts: response.data })
}
render() {
const { contacts } = this.state
return(
<div>
{contacts.map(contact => (
<h1>contact.hello</h1>
))}
</div>
)
}
}
export default Contacts;

Undefined value after fetching API, React

I am building a simple movie catalogue using themoviedb API however I am facing an issue that I am unable to solve.
The issue is that the result after fetching is always undefined.
I tried with the method componentWillMount to fetching data and the setting the state inside this method but it does not work.
I tried to fetch inside constructor, no result.
This is my code so far
import React, { Component } from 'react';
import Header from './components/Header';
import MovieList from './components/MovieList';
import Footer from './components/Footer';
const MOVIE_API = "http://api.themoviedb.org/3/discover/movie?api_key=72049b7019c79f226fad8eec6e1ee889&language=en-US&sort_by=release_date.desc&include_adult=true&include_video=false&page=2&primary_release_year=2018";
//class
class App extends Component {
constructor(props){
super(props);
this.state = {
movies: [],
movieName: ''
}
}
componentWillMount(){
this.fetchMovie();
}
//fetching movie
fetchMovie = () =>{
const req = new Request(MOVIE_API, {
method: 'GET',
cache: 'default'
});
fetch(req).then(response =>{
return response.json();
}).then(data =>{
console.log(data); //REF 1;
this.setState({
movies: data
});
}).catch(err => {
console.log("ERROR: " + err);
})
}
render() {
return (
<div className="root">
<Header />
<MovieList moviesRes={this.state.movies}/>
<Footer />
</div>
);
}
}
export default App;
As you can see I called the method componentWillMount to fetch the data but it does not work.
It is also noticeable that if I log the data (REF 1) I can see the result (json).
===========================
EDIT
This is the code for MovieList
/*import React, { Component } from 'react';
export default class MovieList extends Component{
constructor(props){
super(props);
this.state = {
movies: this.props.movieRes
}
}
render(){
//if result is undefined
if(this.state.movieRes === undefined){
return(
<h1>Loading...</h1>
);
}else{
return(
<ul>
{this.state.movieRes.map((movie, index)=>{
return (
<li key={index}>{movie.title}</li>
);
})}
</ul>
);
}
}
}*/
=================
update child code
import React, { Component } from 'react';
export default class MovieList extends Component{
render(){
const { movieRes = [] } = this.props; // we are assigning a default prop here of an empty array.
return(
<ul>
{
//return movie from array
movieRes.map((movie, index)=>{
return (
<li key={index}>
{movie.id}
</li>
);
})
}
</ul>
);
}
}
In this I way I suppress the error, but still it is not working.
From what I learnt, React should render as soon as it detect changes but for some reason it not the case.
IMAGE
As you can see from the image when I am passing the array from parent component to the child component the array length is 20 but in the child component the array length seems to be 0
===================
Solution
I changed the component from class to a const and pass to it the array and everything went smooth. Here is the final code:
import React from 'react';
const MovieList = ({movies}) =>{
if(!movies){
return <h1>Loading...</h1>
}
return (
<ul>
{
movies.map((movie, index) => {
return (
<li key={index}>
<p>{movie.title}</p>
</li>
)
})
}
</ul>
);
}
export default MovieList;
Originally I misunderstood your issue but after re-reading it I noticed that you defined movies as an array in your constructor.
Without an actual error message, I'm going to assume that MovieList is expecting an array for it's prop movieRes and you're probably then trying to do something like .map or a loop to render the movies.
However, the API you're using doesn't return an array. It returns an object with an array key'd under results. So, I changed it to access data.results when doing setState.
//fetching movie
fetchMovie = () =>{
const req = new Request(MOVIE_API, {
method: 'GET',
cache: 'default'
});
fetch(req).then(response =>{
return response.json();
}).then(data =>{
console.log(data);
this.setState({
movies: data.results // <-- change made here.
});
}).catch(err => {
console.log("ERROR: " + err);
})
}
Here's a working JSFiddle:
https://jsfiddle.net/patrickgordon/69z2wepo/99513/
EDIT:
In the child component, instead of assigning props to state, just use props and default props.
import React, { Component } from 'react';
export default class MovieList extends Component{
render(){
const { movieRes = [] } = this.props; // we are assigning a default prop here of an empty array.
return(
<ul>
{movieRes.map((movie, index)=>{
return (
<li key={index}>{movie.title}</li>
);
})}
</ul>
);
}
}

Categories

Resources