react map is not a function - javascript

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;

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;

State data is being duplicated after using setState inside of componentDidMount

I'm making a get() request to firestore to get data. I am able to store the data in my component state but each time I try to access the data, it shows as duplicated. How can I prevent it? Thanks.
``
import React from 'react';
import fire from '../../config/firebase';
class ViewLists extends React.Component {
constructor(props){
super(props)
this.state = {
listData: []
};
}
componentDidMount(){
fire.firestore().collection('restaurantList')
.get()
.then(querySnapshot => {
const lists = querySnapshot.docs.map(doc => doc.data());
this.setState({ listData: lists });
});
}
render() {
const { listData } = this.state
return (
<div>
{listData.map(list => console.log(list.user))}
</div>
);
}
}
export default ViewLists;
``

Error: Cannot read property 'filter' of undefined, cannot get props

i am getting error while trying to filter out items in array. I suppose it is something connected with not right way to approach state or maybe i am not getting props. Main purpose is to filter trainings based on search value and show them in list.
Source code:
import React from 'react';
import axios from 'axios';
import Trainings from '../components/Training';
import CustomForm from '../components/Form';
class TrainingList extends React.Component {
constructor() {
super();
this.state = {
search: ''
};
}
updateSearch(event) {
this.setState({search: event.target.value.substr(0, 20)})
}
state = {
trainings: []
}
componentDidMount() {
axios.get('http://127.0.0.1:8000/api/')
.then(res => {
this.setState({
trainings: res.data
});
console.log(res.data);
})
}
render() {
let filteredTrainings = this.state.trainings.filter(
(trainings) => {
return trainings.title.indexOf(this.state.
search) !== -1;
}
);
return (
<div>
<Trainings data={filteredTrainings} />
<input type="text"
value={this.state.search}
onChange={this.updateSearch.bind(this)}/>
</div>
)
}
}
export default TrainingList;
You write:
state = {
trainings: []
}
to initialize trainings (You can remove this code). But the data your filtering is this.state.trainings.
So add the initialization of trainings to this.state:
constructor() {
super();
this.state = {
search: "",
trainings: []
};
}

Why this happens with React JS?

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;

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