Why this error arising? users.map is not a function - javascript

I am trying to render names from a API with Axios. Even I can see all data in console but unable to render as it shows error:
users.map is not a function
Below I'm sharing my code of the file. I'm quite new that might be the reason I'm unable to figure it out.
import React from 'react';
import './App.css';
import 'bootstrap/dist/css/bootstrap.min.css'
import { Container, Table} from "react-bootstrap";
import axios from 'axios';
class App extends React.Component {
state = {
users: [],
};
componentDidMount () {
axios.get('https://5w05g4ddb1.execute-api.ap-south-1.amazonaws.com/dev/profile/listAll')
.then(response => {
const users = response.data;
this.setState({ users });
console.log(this.state.users);
})
}
render() {
const { users } = this.state;
return (
<div className="App">
<Container fluid>
<Table striped bordered hover size="sm">
<thead>
<tr>
<th><div id="">Image</div></th>
<th>Name</th>
<th>Gender</th>
<th>Age</th>
<th>Date</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
{ users.map(user => { return <td key={user.id}>{ user.name }</td> }) }
</tr>
</tbody>
</Table>
</Container>
</div>
)
}
}
export default App;

The response you are getting is not an array, but an object like this:
{"list":[{"id":"MnJJA0dbuw","name":"Anand Sharma","img":"https://incablet-tests.s3.ap-south-1.amazonaws.com/conference-content/photos/sponsors/Anand.jpeg","gender":"m","age":46,"date":"23/11/2019","status":"onboarded"}]}
You can access the array by replacing const users = response.data; with const users = response.data.list;

In your axios get, in the “then” part change the line:
const users = response.data;
To:
const users = response.data.list;

fast hack
{users.list.map(user => { return <td key={user.id}>{ user.name }</td> }) }

There are 2 errors:
the response from api is not a list but an object, u need to go to response.list to use the list from the response
it should be
const users = response.data.list
your
this.setState({users})
,you will need to change it to
this.setState({users:<VARIABLE_NAME_TO_HOLD_USER_DATA>})
even what you write is valid like in ES6, that is somehow a bad idea, it is not a clear what are you doing, just define what u want to copy to ur component state

Related

Having trouble implementing pagination into my code using axios

I am a beginner to REACT and I am trying to figure out how to implement pagination into my React project using axios. The api I am using (swapi.dev) has a total of 87 characters, when you submit a GET request with https://swapi.dev/api/people you only get 10 characters per page, but to can use the link in postman, which says "next" to switch between each pages of characters. I am trying to make an request with axios to paginate each list of 10. I figured a for loop would be good to use but I am not sure.
import React, { useEffect, useState } from "react";
import axios from "axios";
import _ from "lodash";
import ReactPaginate from "react-paginate";
import Table from "react-bootstrap/Table";
export default function Posts() {
const [characterData, setCharacterData] = useState([]);
//use a for loop to loop through all sites
useEffect(() => {
axios
.get("https://swapi.dev/api/people/")
.then((res) => {
console.log(res.data.next);
setCharacterData(res.data.results);
})
.catch((err) => {
console.log(err);
});
}, []);
// for ( i = 0; i < data.results.length, i++) {
// names = names + data.results[i].name
// }
// function handleclick(e) => {
// }
return (
<>
<Table stripped bordered hover className="project--table">
<thead>
<tr>
<th>Name</th>
<th>Birth Year</th>
<th>Height</th>
<th>Mass</th>
<th>Homeworld</th>
<th>Species</th>
</tr>
</thead>
<tbody>
{characterData.map((character, index) => {
return (
<tr key={index}>
<td>{character.name}</td>
<td>{character.birth_year}</td>
<td>{character.height}</td>
<td>{character.mass}</td>
<td>{character.homeworld}</td>
<td>{character.species}</td>
</tr>
);
})}
</tbody>
</Table>
{/* <button onClick={}>Next</button> */}
</>
);
I checked your api and the next key have a value that contains the url for the next page. No need for a loop you can just check if the next key exists and depending on that you send a request.
you can create a new state that will contain the next uri and on the onClick function you check if for the "next" key.
it's something like this :
const [next,setNext]= useState("");
in the useEffect you wrote you can add :
axios
.get("https://swapi.dev/api/people/")
.then((res) => {
console.log(res.data.next);
setCharacterData(res.data.results);
if (res.data.next) setNext(res.data.next);
})
and finally in the onClick function :
if(next) {
axios.get(next).then(res=> setCharacterData(res.data.results))
}
I think there is a better solution for this but you can work with this atm.

How to use a component's method to alter an object in another component? [React]

I have a simple app with 3 React components stacked on top of another:
function App() {
return (
<Fragment>
<div className="container">
<ListSuppliers/>
<InputContact/>
<ListContact/>
</div>
</Fragment>
);
}
In my ListSuppliers component I have a dropdown menu, in my InputContact component I have an input form, and in my ListContact I have an html table like so:
return <Fragment>
<h1>List Contact</h1>
<table className="table mt-5">
<thead>
<tr>
<th>Contact Name</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{contacts.map(contact => (
<tr key={contact.contact_id}>
<td>{contact.contact_name}</td>
<td><EditContact contact={contact}/></td>
<td><button className="btn btn-danger" onClick={()=> deleteContact(contact.contact_id)}>Delete</button></td>
</tr>
))}
</tbody>
</table>
</Fragment>
I want my html table in the ListContact component to be populated based on the selection from the menu in the ListSuppliers component:
//Select function
const chooseSupplier = async (id) => {
try {
const response = await fetch(`http://localhost:5000/contact_supplier/${id}`,{
method: "GET"
});
const jsonData = await response.json();
console.log(jsonData);
} catch (err) {
console.log(err.message);
}
}
//Route
app.get("/contact_supplier/:id", async (req, res) => {
try {
const {id} = req.params;
const contact = await pool.query('SELECT * FROM contact WHERE supplier_id = $1 ORDER BY contact_id ASC', [id]);
res.json(contact.rows);
} catch (err) {
console.error(err.message);
}
})
So far I am able to receive the query that I need in json format, however I'm not sure how to query from one component target to an object in another in this case.
You need to maintain the state in the parent component (here - App.js)
for const [state,setState] = useState() and then pass the state and setState to the children where they can access them and call them.

TypeError: Cannot read property 'bind' of undefined, I can not figure what this means. React js

I ran into this error when trying to run my React code and see it's a common error but after looking at other people's questions I am having issues still how to fix this. I am still new to React so I'm kinda lost. What the code is supposed to do is take a JSON file and and display it as a table and the button is supposed to then sort it by last name and redisplay the table.
import data from './data.json' //Imports the JSON from local file, can be changed later to pull from api
import {Button, View} from 'react-native';
export default function App() {
return (
<PaientTable/>
);
}
class PaientTable extends React.Component {
constructor(props) {
super(props);
this.state = { counter: 0 };
// this.sort = this.sort.bind(this);
}
render(){
function sort (){
return this.setState(
data.sort((a, b) => {//sorts by name
if (a.lName < b.lName) {
return -1;
}
if (a.lName > b.lName) {
return 1;
}
return 0;
})
);
}
return (
<table>
<caption>Paients</caption>
<thead>
<tr>
<th>ID</th>
<th>First Name</th>
<th>
<button type="button" onClick={() => this.sort.bind(this)}>
Last Name
</button>
</th>
</tr>
</thead>
<tbody>
{data.map(paient => (
<tr>
<td>{paient.id}</td>
<td>{paient.fName}</td>
<td>{paient.lName}</td>
</tr>
))}
</tbody>
</table>
);
}
}
You've defined sort to be a local variable inside of render, But all the places where you try to access it you're treating it as though its a member of the class. So instead of structuring it like this:
class PaientTable extends React.Component {
// ...
render() {
function sort () {
// ...
}
// ...
}
}
Do this:
class PaientTable extends React.Component {
// ...
sort() {
// ...
}
render() {
// ...
}
}

How to Get a specific question by Id in React

I have a question concerning Mern stack. I have a program which is similar to stackOverflow, where you post a question and someone can reply. At the moment my program is able to post questions and also get a list of all questions. I have a link at each and every questions,so that when you click at any of the questions it should open that specific question. The id of the questions is visible at the rout e.g http://localhost:3000/link/5cae2dda9723ad157c085370. The problem am having is to get the content of that specific question
//*this code is able get the list of all questions*//
import React, { Component } from "react";
import { Link } from "react-router-dom";
import axios from "axios";
import { EMLINK } from "constants";
const Question = props => (
<tr>
<td>{props.question.author_name}</td>
<td>{props.question.question_title}</td>
<td>{props.question.question_input}</td>
<td>
<Link to={"/link/" + props.question._id}>comment</Link>
</td>
</tr>
);
class QuestionList extends Component {
constructor(props) {
super(props);
this.state = { questions: [] };
}
componentDidMount() {
axios
.get("http://localhost:4000/questions/")
.then(response => {
this.setState({ questions: response.data });
})
.catch(function(error) {
console.log(error);
});
}
questionList() {
return this.state.questions.map(function(currentQuestion, i) {
return <Question question={currentQuestion} key={i} />;
});
}
render() {
return (
<div>
<h3>Question List</h3>
<table className="table table-striped" style={{ marginTop: 20 }}>
<thead>
<tr>
<th>Name</th>
<th>Title</th>
<th>Question</th>
<th>Action</th>
</tr>
</thead>
<tbody>{this.questionList()}</tbody>
</table>
</div>
);
}
}
export default QuestionList;
*/The below code is the one that i need to only show one specific question by ID*//
import React, { Component } from "react";
import { Link } from "react-router-dom";
import axios from "axios";
const Questioners = props => (
<tr>
<td>{props.question.author_name}</td>
<td>{props.question.question_title}</td>
<td>{props.question.question_input}</td>
</tr>
);
class QuestionLink extends Component {
constructor(props) {
super(props);
this.state = {
author_name: "",
question_title: "",
question_input: ""
};
}
render() {
return (
<div>
<h3>Question List</h3>
<table className="table table-striped" style={{ marginTop: 20 }}>
<thead>
<tr>
<th>Name</th>
<th>Title</th>
<th>Question</th>
</tr>
</thead>
<tbody>{}</tbody>
</table>
</div>
);
}
}
export default QuestionLink;
I've done the following in these scenarios:
Take the ID as a parameter to the Component (in this case, QuestionLink)
Retrieve the question from your REST API as a get for the particular resource (with ID) in your ComponentDidMount
When mounting your react app (top-level component), retrieve the Id from the url. I prefer to use a query string
import { parse } from "querystring";
let values = parse(window.location.search.substring(1));
And then mount <QuestionLink questionId={values["questionId"]} />
EDIT: I haven't used template engines for this, but it should be well suited for this kind of work. You can use something like pug for the server side rendering, pass the id to the view from your middleware, and render to a react component. I'd probably only do this if I did this sort of processing extensively and/or needed information that only the server had.
Thanks for help, i made it work. i solved the issue as follow
<Route
path="/link/:id"
render={props => <QuestionLink {...props} />}
/>
this.state = {
currentQuestion: {}
};
componentDidMount() {
axios
.get("http://localhost:4000/questions/")
.then(response => {
this.setState({
currentQuestion: response.data.find(elm =>
elm._id == this.props.match.params.id
)
});
})

ReactJS: React Component not rendering

ContactList.js
var React = require('react');
var Contact = require('./contact.js');
var ContactList = React.createClass({
render: function() {
return(
<div>
<h3>Contacts</h3>
<table className="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Number</th>
<th>Email</th>
<th></th>
</tr>
</thead>
<tbody>
{
this.props.contacts.map(function(contact, index) {
<Contact contact={contact} key={index} />
})
}
</tbody>
</table>
</div>
)
}
Contact.js
var React = require('react');
var Contact = React.createClass({
render: function() {
return(
<tr>
<td>{this.props.contact.name}</td>
<td>{this.props.contact.phone}</td>
<td>{this.props.contact.email}</td>
</tr>
)
}
})
module.exports = Contact;
Basically, i am able to get the contacts data from firebase in console but i want to display all the contacts i saved in the table. Behind the scenes, there is react-flux setup. State 'contacts' is basically an object inside an array, when i go to react tools, i can't see Contact component there, also if i try to console.log something to verify nothing works in Contact component, it seems like props is not passing to Contact component, also sometimes i get
[Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. don't know whether it is because of this.
Can somebody explain me what is wrong ? Thanks in advance!!.
You need to send props to ContactList.js i.e, the response.data that you get after hitting firebase.
Something like this:-
React.render(<ContactList contacts= 'your response object' />);
Check whether your passing or not.
To solve it more easily you can use React.Component ,
ContactList.js
import React from 'react';
import Contact from './contact'
class ContactList extends React.Component {
{contacts}=this.props;
render(){
return(
<div>
<h3>Contacts</h3>
<table className="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Number</th>
<th>Email</th>
<th></th>
</tr>
</thead>
<tbody>
{
contacts.map(function(contact, index) {
<Contact contact={contact} key={index} />
})
}
</tbody>
</table>
</div>
)
}
}
export default ContactList
Contact.js
import React from 'react'
class Contact extends React.Compponet{
{contact}=this.props;
render() {
return(
<tr>
<td>{contact.name}</td>
<td>{contact.phone}</td>
<td>{contact.email}</td>
</tr>
)
}
}
export default Contact
You have to pass the props to the ContactList class which would internally pass it to Contact.
Thank you.
You need to return the Contact component inside the ContactList component like this:
this.props.contacts.map(function(contact, index) {
return <Contact contact={contact} key={index} />
})
or, you can use arrow function:
this.props.contacts.map((contact, index) => <Contact contact={contact} key={index} />)

Categories

Resources