After many attempts I fail to use arrays from https://swapi.co/api/
What I want is to use data from people and films.
I have 2 files :
App.js
import React, { Component } from "react";
import List from './List';
const API = 'https://swapi.co/api/';
class App extends Component {
constructor(props) {
super(props);
this.state = {
data: []
};
}
componentWillMount() {
this.fetchData();
}
fetchData = async () => {
const response = await fetch(API);
const json = await response.json();
this.setState({
data: json.data
});
};
render() {
return (
<List data={this.state} />
);
}
}
List.js
import React, { Component } from 'react';
import Person from './Person';
class List extends Component {
render() {
const { data } = this.props;
const { results } = data;
return (
<div className="flex-grow-1">
<div className="row mb-5">{results}</div>
</div>
);
}
}
export default List;
So, how do I go through that array to get what data I want to display ? I'd like to render people -> results and films -> results
results would be undefined since results is not a node within your data object... try removing the line const {results} = data and in the return map the data array:
return (
<div className="flex-grow-1">
{
data.map((results, i) => {
return (<div key={i} className="row mb-5">{results}</div>);
})
}
</div>
);
you will need the key to avoid React's unique key warning
So this code as it is now will fetch the single object that acts as a map of other urls for entities in this API. what you want to do is modify fetchData so it accepts a url. At that moment you can do an initial request to /api, read the url from the result for people and films and call fetchData again with these urls. The received data can be saved inside the state.
A example for the implementation of componentWillMount() and fetchData():
componentWillMount() {
this.fetchData('https://swapi.co/api/')
.then(res => {
this.fetchData(res.people).then(people => alert(JSON.stringify(people)));
this.fetchData(res.films).then(people => alert(JSON.stringify(people)));
});
}
async fetchData(url) {
const response = await fetch(url);
return response.json();
};
The most important change is that fetchData now returns a promise. That allows us to use the then method to use the result of the first request. You can replace the alert with a setState implementation for yourself.
Related
I'm trying to create dynamic headers using state in NextJs, my values however are blank when I view the page source. I suspect my state is not being resolved before the render method fires. Why would the rest of my content load in the render method but not the head ? Example code:
import Head from 'next/head'
myContent() {
const {name} = this.state
return (
<h1>{name}</h1>
)
}
render() {
const {myDescription} = this.state
return (
<>
<Head>
<meta name='description' content={myDescription} />
</Head>
{this.myContent()}
</>
)
}
export async function getServerSideProps() {
const fetchMyData = await fetch('https://myapi.com')
const fetchedMyData = await fetchMyData.json()
return {
props: {
data: fetchedMyData.entries,
}
}
}
I've also tried moving the head into the myContent() method. Same issue.
So turns out I was attempting to pass client side data to the server. I needed to utilise the context param then retrieve from props.
componentDidMount() {
console.log(this.props)
}
export async function getServerSideProps(context) {
const { params } = context
const fetchMyData = await fetch('https://myapi.com')
const fetchedMyData = await fetchMyData.json()
return {
props: {
data: fetchedMyData.entries,
params,
}
}
}
From Starships I get only array of urls I would like to fetch these url adresses and get name of each starship. I tried to do it throuht map array but I probably donĀ“t know to write it. Do you have any ideas?
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(props){
super(props);
this.state = {
movies:[],
starships:[],
}
}
//we fetch all data and store it to movies
async componentDidMount() {
return await fetch("https://swapi.dev/api/films/")
.then(result => result.json())
.then(data =>
this.setState({
movies: data.results
})
)
}
render(){
console.log(this.state.movies);
return (
<div className="App">
<h1>Movies</h1>
<div className="moviesList">
{this.state.movies.map((movie, index) => {
return <p key={index} >{movie.title}</p>
})}
</div>
<div className="starshipsList">
{this.state.movies.map((starship, index) => {
return <p key={index} >{starship.starships}</p>
})}
</div>
</div>
);
}
}
export default App;
You should check if the API doesn't provide another endpoint for starships as what are you trying to do isn't a best approach in my opinion.
But if it doesn't and you still need starship list, something like this could work:
async componentDidMount() {
// get movies
const moviesResult = await fetch("https://swapi.dev/api/films/");
const movies = await moviesResult.json();
// get array of all urls
const starshipsUrls = movies.results.reduce((acc, movie) => {
return acc.concat(movie.starships);
},[]);
// map over the urls and use promise.all to fetch
const starshipsResult = await Promise.all(starshipsUrls.map(url=> fetch(url)));
const starships = starshipsResult.json();
this.setState({
movies,
starships
});
}
import React, { useEffect, useState } from "react";
import { toast } from "react-toastify";
const Dashboard = ({ setAuth }) => {
const [name, setName] = useState("");
const [role, setRole] = useState("");
const getProfile = async () => {
try {
const res = await fetch("http://localhost:5000/dashboard/", {
method: "POST",
headers: { jwt_token: localStorage.token }
});
const parseData = await res.json();
console.log(parseData)
setRole(parseData.user_role);
setName(parseData.user_name);
} catch (err) {
console.error(err.message);
}
};
const logout = async e => {
e.preventDefault();
try {
localStorage.removeItem("token");
setAuth(false);
toast.success("Logout successfully");
} catch (err) {
console.error(err.message);
}
useEffect(() => {
getProfile();
}, []);
return (
<div>
<h1 className="mt-5">Dashboard</h1>
<h2>Welcome {name} as {role}</h2>
<button onClick={e => logout(e)} className="btn btn-primary">
Logout
</button>
</div>
);
};
export default Dashboard;
Hi all,
Please help...
I am trying to develop an app with a simple login registration .
I have a code in function component for login registration which I have posted above .
My entire codes of the app are in class based(class components). Could you please help me to convert the above code into
class based.
You can convert your function component to a class in five steps:
Create an ES6 class, with the same name, that extends React.Component.
Add a class constructor that assigns the initial this.state (to add your initial state of name and role ).
use this.setState to update your state ( name or role).
Add a single empty method to it called render().
Move the body of "return" inside the function component into the render() method.
Replace props with this.props in the render() body.
you can't use react Hooks (useEffect, useState ) inside you class component , so you will need to use ComponentDidMount or ComponentDidUpdate ...(depending in the situation ), in your case you will need to use ComponentDidMount because you fetching data (call getProfile inside ComponentDidMount).
you need to take a look in the references below to understand more about it and why you will need to use componentDidMount:
https://reactjs.org/docs/state-and-lifecycle.html#converting-a-function-to-a-class
https://daveceddia.com/where-fetch-data-componentwillmount-vs-componentdidmount/
I have a container component in which I get the ID and drop this ID into the function and the request goes, in principle, the props should come right away, but they are undefined. But when you re-enter the same component, the necessary props are shown.
Explain how to make props appear on the first render?
class View extends React.Component {
componentDidMount() {
let id = this.props.match.params.id;
this.props.GetProjData(id);
}
render() {
return <ProjView {...this.props}></ProjView>;
}
}
let mapStateToProps = state => {
return {
initialValues: {
NameProj: state.project.OneProject.NameProj,
Text: state.project.OneProject.Text,
target: state.project.OneProject.target,
startdate: state.project.OneProject.startdate,
enddate: state.project.OneProject.enddate
},
error: state.settings.error,
loading: state.settings.loading
};
};
My request
export const GetProjData = data => async (
dispatch,
getState,
{ getFirestore }
) => {
const firestore=getFirestore()
try {
await firestore
.collection("Projects")
.where("idProject", "==", data)
.get().then(snap => {
snap.forEach(doc => {
let project=doc.data()
console.log(doc.data());
dispatch({type:getOne,project})
});
})
} catch (err) {}
};
If I'm understanding the flow of your app correctly, you need to account for the renders between when you request your project data and when you receive the project data.
class View extends React.Component {
// constructor fires first so we might as well move it here
constructor(props) {
const id = props.match.params.id;
props.GetProjData(id);
}
render() {
// Your component will rerender before receiving the new data.
// We block the component from mounting so that initialValues
// gets set only when we have the data needed
if (this.props.initialValues && this.props.initialValues.NameProj) {
// A better way to do this would be to listen to a loading variable
// that gets updated when your request finishes
return <ProjView {...this.props} />;
}
return null; // or loading graphic
}
}
I am trying to display a list of user repositories. Through the spread operator attempts to spell the object. However, I do not know if this is a good method, there are no errors in the console, but nothing appears on the screen. This is my code.
class ItemUserDetail extends React.Component {
constructor() {
super();
this.state = {
usersRepos: []
};
}
componentDidMount() {
const { user } = this.props.match.params;
const url = `https://api.github.com/users/${user}/repos`;
fetch(url)
.then(res => res.json())
.then(json => this.setState({ usersRepos: json }));
}
render() {
const Repos = this.state.usersRepos ? { ...this.state.usersRepos } : null;
return (
<div>
<p>{Repos.name}</p>
</div>
);
}
}
export default ItemUserDetail;
Since you are returning an array of repositories, your render method should look like this
render() {
const Repos = this.state.usersRepos ? this.state.usersRepos : null; // you don't need this
const { userRepos } = this.state; // destructure
return (
<div>
{userRepos.map(repo => <p key={repo.id}>{repo.name}</p>)}
</div>
);
}