I'm trying to build website consist of one page containing many components.
I want to fetch data for each component
so I try use Promise.all() in index page
but the problem is that translations from API don't appear only one language appears.
I used Next.js Internationalized Routing,
but when I only make axios.get() for one component it works.
What is the problem & how can I solve that?
header.js
import Link from 'next/link';
import { useRouter } from 'next/router';
import en from './locales/en';
import ar from './locales/ar';
import Axios from 'axios';
import Cookie from 'js-cookie';
import {useState } from 'react';
const Header = () => {
const router = useRouter();
const [langCode, setLangCode] = useState('en');
Axios.defaults.headers.common['Language'] = langCode;
const { locale } = router;
const t = locale === 'en' ? en : ar;
const changeLanguage = (locale) => {
Cookie.set('lang', locale);
router.push(router.pathname, router.asPath, { locale });
setLangCode(locale);
};
const lang = Cookie.get('lang')
return (
<header>
<button onClick={() => changeLanguage(lang == 'en' ? 'ar' : 'en')}>
change lang
</button>
<ul>
<li>
<Link href="/">
<a>{t.home}</a>
</Link>
</li>
</ul>
</header>
);
};
export default Header;
index.js
import Axios from "axios";
import Header from "../components/Header";
const index = ({ data }) => {
return (
<div>
<Header />
<div dangerouslySetInnerHTML={{ __html: data.details}}/>
</div>
);
};
index.getInitialProps = async () => {
const res = await Axios.get(`https://api.trueapps.co/api/who-we-are`);
const data = await res.data.data;
return { data };
};
export default index;
AND this is the code in index.js when I use Promise.all().
index.js
import Axios from "axios";
import Header from "../components/Header";
const index = (data) => {
console.log(data.about);
console.log(data.services);
console.log(data.team);
return (
<div>
<Header />
</div>
);
};
index.getInitialProps = async () => {
const [about, team, services] = await Promise.all([
fetch(`https://api.trueapps.co/api/who-we-are`).then((r) => r.json()),
fetch(`https://api.trueapps.co/api/team`).then((r) => r.json()),
fetch(`https://api.trueapps.co/api/services`).then((r) => r.json()),
]);
return { about, team, services};
};
export default index;
The issue is that you're setting the default Language header in axios (Axios.defaults.headers.common['Language'] = langCode;) but then making the requests using fetch.
Using axios to make the requests in index.getInitialProps should do the trick.
index.getInitialProps = async () => {
const [aboutRes, teamRes, servicesRes] = await Promise.all([
Axios.get(`https://api.trueapps.co/api/who-we-are`),
Axios.get(`https://api.trueapps.co/api/team`),
Axios.get(`https://api.trueapps.co/api/services`)
]);
return {
about: aboutRes.data,
team: teamRes.data,
services: servicesRes.data
};
};
Looks like you are mixing Axios and fetch API together. Maybe you need to change to Axios's get instead of fetch API from the below code.
index.getInitialProps = async () => {
const [about, team, services] = await Axios.all([
await fetch(`https://api.trueapps.co/api/who-we-are`).then((r) => r.json()),
fetch(`https://api.trueapps.co/api/team`).then((r) => r.json()),
fetch(`https://api.trueapps.co/api/services`).then((r) => r.json()),
]);
return { about, team, services};
};
Related
Introducing The Problem
I am beginner ReactJS learner developing a simple weather app using OpenWeather API. The app is designed to fetch data from two components: one that returns the current weather of the user input and another one that returns the weather forecast for the next 5 days.
When the city name is typed down into the input field, the following message appears on the console:
GET https://api.openweathermap.org/data/2.5/weather?q=undefined&units=metric&appid=${Api.key} 400 (Bad Request)
I do not know how to pass the data from Search Component into App Component. Seriously, I have tried a lot of alternatives but they have been unsuccessful. There are commented lines of code to show my last try so far.
(ignore ForecastWeather because this component is empty)
I know that all of you are quite busy folks, but I would appreciate the help in a respectful way. Even suggestions about what I have to study (e.g. callBack) are welcome. I've tried this already:
https://stackoverflow.com/questions/56943427/whether-to-save-form-input-to-state-in-onchange-or-onsubmit-in-react
https://sebhastian.com/react-onchange/
The code is forward below:
App.js
import React, { useState } from "react";
import { Api } from "./Api";
import {
Search,
CurrentWeather,
ForecastWeather,
Footer,
} from "./components/index";
import "./App.css";
function App() {
const [getCity, setGetCity] = useState();
const [weatherData, setWeatherData] = useState(null);
const [forecastData, setForecastData] = useState(null);
const handleSearchLocation = (dataSearch) => {
const weatherDataFetch = fetch(
`${Api.url}/weather?q=${getCity}&units=metric&appid=${Api.key}`
);
const forecastDataFetch = fetch(
`${Api.url}/forecast?q=${getCity}&units=metric&appid=${Api.key}`
);
Promise.all([weatherDataFetch, forecastDataFetch])
.then(async (response) => {
const weatherResponse = await response[0].json();
const forecastResponse = await response[1].json();
setGetCity(dataSearch);
setWeatherData(weatherResponse);
setForecastData(forecastResponse);
})
.catch(console.log);
};
return (
<div className="App">
<Search
searchResultData={handleSearchLocation}
textPlaceholder="Search for a place..."
/>
{weatherData && <CurrentWeather resultData={weatherData} />}
<ForecastWeather resultData={forecastData} />
<Footer />
</div>
);
}
export default App;
Search.jsx
import React, { useState } from "react";
function Search({ textPlaceholder, searchResultData }) {
const [searchCity, setSearchCity] = useState("");
//const handlerOnChange = ( event, dataSearch ) => {
//setSearchCity(event.target.value);
//setSearchCity(dataSearch);
//searchResultData(dataSearch);
//};
return (
<div className="componentsBoxLayout">
<input
value={searchCity}
//onChange={handlerOnChange}
onChange={(event) => setSearchCity(event.target.value)}
onKeyDown={(event) => event.key === "Enter" && searchResultData(event)}
placeholder={textPlaceholder}
/>
</div>
);
}
export default Search;
CurrentWeather.jsx
import React from "react";
function CurrentWeather({ resultData }) {
return (
<div className="componentsBoxLayout">
<p>{resultData.name}</p>
</div>
);
}
export default CurrentWeather;
ForecastWeather.jsx (empty)
import React from 'react';
function ForecastWeather() {
return (
<div className="componentsBoxLayout">ForecastWeather</div>
)
}
export default ForecastWeather;
Api.js
const Api = {
url: "https://api.openweathermap.org/data/2.5",
key: "etcetc",
img: "https://openweathermap.org/img/wn",
};
export { Api };
Yippee-ki-yay
You can not use getCity in this function:
const handleSearchLocation = (dataSearch) => {
const weatherDataFetch = fetch(
`${Api.url}/weather?q=${getCity}&units=metric&appid=${Api.key}`
);
const forecastDataFetch = fetch(
`${Api.url}/forecast?q=${getCity}&units=metric&appid=${Api.key}`
);
Promise.all([weatherDataFetch, forecastDataFetch])
.then(async (response) => {
const weatherResponse = await response[0].json();
const forecastResponse = await response[1].json();
setGetCity(dataSearch);
setWeatherData(weatherResponse);
setForecastData(forecastResponse);
})
.catch(console.log);
};
getCity is defined on that function so it does not exist when you try to use it, unless you need getCity later for another component I would delete it becuase is redundant and do this:
const handleSearchLocation = (dataSearch) => {
const weatherDataFetch = fetch(
`${Api.url}/weather?q=${dataSearch}&units=metric&appid=${Api.key}`
);
const forecastDataFetch = fetch(
`${Api.url}/forecast?q=${dataSearch}&units=metric&appid=${Api.key}`
);
Promise.all([weatherDataFetch, forecastDataFetch])
.then(async (response) => {
const weatherResponse = await response[0].json();
const forecastResponse = await response[1].json();
setWeatherData(weatherResponse);
setForecastData(forecastResponse);
})
.catch(console.log);
};
When you run searchResultData on the search component you send the city you are looking for. Remember that useState will trigger a re-render but a function that is already running before that will never get the new value of the state if the state changes
I want to create an e-commerce platform that requires pages rendered on the server (initial state computed on the server) but with react or vue components for filtering that change the initial state by fetching the filtered data using api calls.
Do you know any javascript framework that support combining server and client side rendering in one route/page ?
Next JS can make this happen. It supports both server and client side rendering.
Here is an example that combines both :
import { useState } from 'react'
import { useRouter } from 'next/router'
function EventList({ eventList }) {
const [events, setEvents] = useState(eventList)
const router = useRouter()
const fetchSportsEvents = async () => {
const response = await fetch('http://localhost:4000/events?category=sports')
const data = await response.json()
setEvents(data)
router.push('/events?category=sports', undefined, { shallow: true })
}
return (
<>
<button onClick={fetchSportsEvents}>Sports Events</button>
<h1>List of events</h1>
{events.map(event => {
return (
<div key={event.id}>
<h2>
{event.id} {event.title} {event.date} | {event.category}
</h2>
<p>{event.description}</p>
<hr />
</div>
)
})}
</>
)
}
export default EventList
export async function getServerSideProps(context) {
const { query } = context
const { category } = query
const queryString = category ? 'category=sports' : ''
const response = await fetch(`http://localhost:4000/events?${queryString}`)
const data = await response.json()
return {
props: {
eventList: data
}
}
}
How to pass the {requests} prop to the RequestRow component after executing the setRequests? My understanding is that the requests get initialized as undefined in the beginning and before being set with the asynchronously called object, it gets passed to the RequestRow component as undefined, and the error occurs.
import React, { useState, useEffect } from 'react';
import 'semantic-ui-css/semantic.min.css';
import Layout from '../../../components/Layout';
import { Button } from 'semantic-ui-react';
import { Link } from '../../../routes';
import Campaign from '../../../blockchain/campaign';
import { Table } from 'semantic-ui-react';
import RequestRow from '../../../components/RequestRow';
const RequestsIndex = ({ address }) => {
const { Header, Row, HeaderCell, Body } = Table;
const campaign = Campaign(address);
const [requestCount, setRequestCount] = useState();
const [requests, setRequests] = useState([]);
const getRequests = async () => {
const count = await campaign.methods.getRequestsCount().call();
setRequestCount(count);
};
let r;
const req = async () => {
r = await Promise.all(
Array(parseInt(requestCount))
.fill()
.map((_element, index) => {
return campaign.methods.requests(index).call();
})
);
setRequests(r);
};
useEffect(() => {
getRequests();
if (requestCount) {
req();
}
}, [requestCount]);
return (
<Layout>
<h3>Requests List.</h3>
<Link route={`/campaigns/${address}/requests/new`}>
<a>
<Button primary>Add Request</Button>
</a>
</Link>
<Table>
<Header>
<Row>
<HeaderCell>ID</HeaderCell>
<HeaderCell>Description</HeaderCell>
<HeaderCell>Amount</HeaderCell>
<HeaderCell>Recipient</HeaderCell>
<HeaderCell>Approval Count</HeaderCell>
<HeaderCell>Approve</HeaderCell>
<HeaderCell>Finalize</HeaderCell>
</Row>
</Header>
<Body>
<Row>
<RequestRow requests={requests}></RequestRow>
</Row>
</Body>
</Table>
</Layout>
);
};
export async function getServerSideProps(context) {
const address = context.query.address;
return {
props: { address },
};
}
export default RequestsIndex;
The RequestRow component is shown below. It takes in the {requests} props, which unfortunately is undefined.
const RequestRow = ({ requests }) => {
return requests.map((request, index) => {
return (
<>
<div>Request!!!</div>
</>
);
});
};
export default RequestRow;
The snapshot of the error is shown below:
I think React is trying to render your component before your promises resolve. If that's the case, all you need to do is set a default value (an empty array in your case) for your requests.
const [requests, setRequests] = useState([]);
May the force be with you.
i am trying to show up the single blog page in my next project.
i get the error at getStaticProps
i tried make the data that is coming from the api an array but it doesn't work also , i don't know where the issue of this code everything looks fine
i don't know if the error from the api or something else.
import { useRouter } from 'next/router';
import Link from 'next/link';
import BlogsStyle from '../../../styles/Blogs.module.css';
import { Image } from "react-bootstrap";
const Blog = ({ blog }) => {
const router = useRouter()
const {id} = router.query
return (
<div>
<div className={BlogsStyle.blogItem}>
<div className={BlogsStyle.blogImg}>
<Image className={BlogsStyle.blogImgSrc} src={blog.image_url} alt="image blog" onError={(e)=>{e.target.onerror = null; e.target.src="../../public/images/default_blog.png"}} fluid />
</div>
<div className=" blog__item--text">
<div className="info">
<div className="date">{blog.publish_date}</div>
<h6>{blog.title.ar}</h6>
<p>{strip(blog.content.ar).substring(0,100)}</p>
</div>
</div>
</div>
</div>
)
}
export const getStaticPaths = async () => {
const res = await fetch('https://masahefapi.slsal.co/pgarticles/articles/0/10');
const data = await res.json();
console.log(data);
const paths = await data.map(blog =>{
return {
params: { id: blog.id.toString() }
}
})
return {
paths,
fallback: false
}
}
export const getStaticProps = async({ params }) => {
const id = context.params.id;
const res = await fetch(`https://masahefapi.slsal.co/pgarticles/articles/0/10/${params.id}`);
const data = await res.json();
console.log(data);
return {
props: {
blog: data
}
}
}
export default Blog
it doesn't show an error and the project works just fine. I can log the data to the console as well. but it doesn't display in the UI. this is a tutorial project on youtube
I'm getting data from the API and passing that to the tours and tour components. and Tour component displays the fetched data.
App component
import React, { useState, useEffect } from "react";
import Loading from "./Loading";
import Tours from "./Tours";
// ATTENTION!!!!!!!!!!
// I SWITCHED TO PERMANENT DOMAIN
const url = "https://course-api.com/react-tours-project";
function App() {
const [loading, setLoading] = useState(true);
const [tours, setTours] = useState([]);
const fetchTours = async () => {
try {
const response = await fetch(url);
const tours = await response.json();
setLoading(false);
setTours(tours);
} catch (error) {
setLoading(true);
console.log(error);
}
};
useEffect(() => {
fetchTours();
}, []);
if (loading) {
return (
<main>
<Loading />
</main>
);
}
return (
<main>
<Tours tours={tours} />
</main>
);
}
export default App;
Tours component
import React from "react";
import Tour from "./Tour";
const Tours = ({ tours }) => {
return (
<section>
<div className="title">
<h2>Our Tours</h2>
<div className="underline"></div>
</div>
<div>
{tours.map((tour, index) => {
return <Tour key={tour.id} {...tours} />;
})}
</div>
</section>
);
};
export default Tours;
Tour Component
import React, { useState } from "react";
const Tour = ({ id, image, info, price, name }) => {
return (
<article className="single-tour">
<img src={image} alt={name} />
<footer>
<div className="tour-info">
<h4>{name}</h4>
<h4 className="tour-price">AUD{price}</h4>
</div>
<p>{info}</p>
<button className="delete-btn">Not Interested</button>
</footer>
</article>
);
};
export default Tour;
Try this code:
useEffect(async () => {
await fetchTours();
}, []);
I think your UI has not updated after the data arrived. You need to wait for your data is fetched.
Try to remove the setting of state in the function and move it to use effect. Have the API call only return the list instead of having it retrieving the list and setting the state.
const fetchTours = async () => {
const response = await fetch(url);
const tours = await response.json();
return tours;
};
useEffect(() => {
const fetchAndSetTourState = async () => {
const data = await fetchTours();
setTours(data);
setLoading(false);
}
fetchAndSetTourState();
}}, []);