so my problem is, that I have two variables called stories, one of which is from the React lib and the other one in my code. The problem is, that it passes the wrong stories variable, which then gives me the error: "TypeError: stories.map is not a function", because its taking the React stories variable and not the variable I created myself. Down below is the picture where I explain it with a graphic.enter image description here
import React, {Component} from "react";
import fetch from 'isomorphic-fetch'
import Error from 'next/error'
class Index extends React.Component {
static async getInitialProps() {
let stories
try {
const response = await fetch('https://node-hnapi.herokuapp.com/news?page=1')
stories = await response.json()
} catch (err) {
console.log(err)
stories = []
}
return { stories };
}
render() {
const {stories} = this.props
if(stories.length === 0) {
return <Error statusCode={503}/>
}
return (
<div>
<h1>hacker next</h1>
<div>
{stories.map(story => (
<h2 key={story.id}>{story.title}</h2>
))}
</div>
</div>
);
}
}
export default Index;
Related
I am having trouble doing a fetch according to the documentation available on the Next.js website. I have tried to console the props, which I can't get to show up. I don't have experience with Next, trying to mirror it to React, but unfortunately it's not working. How can I do a fetch using getStaticProps? I have a tutorial that is using getInitialProps for an older version of Next.js, but I am trying to follow their new documentation. Here is the starter code I have so far:
import React, { Component } from 'react';
// import fetch from 'node-fetch'
class Index extends Component {
state = {}
getStaticProps = async () => {
// Call an external API endpoint to get posts.
console.log('fetching data')
const res = await fetch('https://jsonplaceholder.typicode.com/todos/1')
const posts = await res.json()
return {
props: {
posts,
},
}
}
render() {
console.log(this.props)
return (
<div>
<h1>Our Index Page!!</h1>
</div>
);
}
}
export default Index
From the docs:
If you export an async function called getStaticProps from a page, Next.js will pre-render this page at build time using the props returned by getStaticProps.
That means that instead of having your getStaticProps inside the component, export it as such:
import React, { Component } from 'react';
// import fetch from 'node-fetch'
class Index extends Component {
state = {}
render() {
console.log(this.props)
return (
<div>
<h1>Our Index Page!!</h1>
</div>
);
}
}
export const getStaticProps = async () => {
// Call an external API endpoint to get posts.
console.log('fetching data')
const res = await fetch('https://jsonplaceholder.typicode.com/todos/1')
const posts = await res.json()
return {
props: {
posts,
},
}
}
export default Index
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 :)
I'm trying to fetch usersList using axios api
But I got an error below:
How to solve this problem?
I attached my code
I think renderUsers function has a problem...
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchUsers } from '../actions';
class UsersList extends Component {
componentDidMount(){
// this.props.fetchUsers();
console.log("It called....")
}
renderUsers(){
console.log("renderUsers()")
return this.props.users.map(user => {
return <li key={user.id}>{user.name}</li>;
})
}
render(){
return (
<div>
Here's a big list of users:
<ul>{this.renderUsers()}</ul>
</div>
)
}
}
function mapStateToProps(state){
return { users: state.users };
}
export default connect(mapStateToProps, { fetchUsers })(UsersList);
You first remove comment from this.props.fetchUsers(); in componentDidMount so it could fire API and get the response.
Now component will render(at least first time) even before we get response from API. in that case this.props.users is undefined.
So check if this.props.users before you map it.
renderUsers(){
console.log("renderUsers()")
return this.props.users && this.props.users.map(user => {
return <li key={user.id}>{user.name}</li>;
})
}
It's likely that in your parent component, you have something like: let users;. This means it's being passed as undefined and messing up your map(). So, try declaring it as let user = {} instead.
this.props.users is undefined before it is an Array. You should add a check before using [Array.map()][1]
renderUsers(){
console.log("renderUsers()");
const { users } = this.props;
return Array.isArray(users) && users.map(u=> <li key={u.id}>{u.name}</li>);
}
or add a defaultProp in your component
class UsersList extends Component {
static defaultProps = {
users: []
}
}
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>
);
}
}
I want to pass data from axiosDidMount function to
<p className='title' id='boldTitle'>{data goes here}</p>
I can console.log data and it is working and in my example it is a string "New York City".
I got to the point when I write some input in Search.js Component and it is passed to Results.js Component by this.props.userQuery. So the response.data[1][1] is updating correctly and live in console.log as I write input but I have problem with passing this data that I'm getting from Wikipedia to final destination.
What is proper way to pass this data in this example?
import React from 'react';
import axios from 'axios';
export default class Results extends React.Component {
axiosDidMount(userQuery) {
//const fruits = [];
const wikiApiUrl = 'https://en.wikipedia.org/w/api.php?action=opensearch&format=json&origin=*&search=';
const wikiApiUrlWithQuery = wikiApiUrl + userQuery;
axios.get(wikiApiUrlWithQuery)
.then(response => {
console.log(response.data[1][1]); //New York City
console.log(typeof(response.data[1][1])); //string
//console.log(response.data[2])
//console.log(response.data[3])
//fruits.push(response.data[1]);
})
.catch(err => {
console.log('Error: =>' + err);
});
//return fruits;
}
render() {
//this.props.userQuery from Search.js
const test = this.axiosDidMount(this.props.userQuery);
return(
<div>
<a className='title' href="" target='_blank'>
<div className='result'>
<p className='boldTitle'>{data goes here}</p>
<p></p>
</div>
</a>
</div>
);
}
}
You should separate your concerns. Make a data receiving component, or a container component that handles data retrieval and conditionally renders the component requiring the data once it's available. Something along the lines of the following:
import React, { Component } from 'react';
import axios from 'axios';
const PresentationComponent = (props) => {
// return mark with data
}
const PlaceHolderComponent = (props) => {
// return placeholder markup
}
export default class DataReceivingWrapper extends Component {
constructor(props) {
super(props);
this.state = {
data: null
}
}
componentDidMount() {
axios.get(...)
.then(data) {
this.setState(Object.assign({}, this.state, { data: data }))
}...
}
render() {
if (this.props.data) {
return <PresentationComponent />;
} else {
return <PlaceHolderComponent />; // or null
}
}
}