getInitialProps does not work with async function - javascript

I have file in this path ./pages/blog/[id]/[title].js and here are the codes that I have written :
import React from 'react';
import PropTypes from 'prop-types';
import fetch from 'isomorphic-unfetch';
import BASE_URL from '../../../BaseURL';
const BlogSinglePage = props => {
console.log(props.post);//undefined
console.log(props);//{}
return (
<div></div>
);
};
BlogSinglePage.propTypes = {
post: PropTypes.object
};
BlogSinglePage.getInitialProps = async ({ query }) => {
const res = await fetch(`${BASE_URL}/api/post/${query.id}`);
const post = await res.json();
return { post };
};
export default BlogSinglePage;
my problem is when getInitialProps is an async function , BlogSinglePage 's props is empty but whenever getInitialProps is not an async function , everything works and props is not empty
I have followed the code in Implement the Post Page line by line but it's not working for me

I have no idea why this was the problem ,
but i reinstall next js with next-cli and the problem was solved :)

Related

How to Refactor an Async Function out of a React Component

I have a straightforward react component that looks so in AllWords.js :
import React, { useEffect, useState } from 'react';
import consts from '../../constants/Constants.js';
function AllWords() {
const [words, setWords] = useState([]);
async function fetchData(){
const response= await fetch(consts.FETCH_URL);
const data = await (response.json());
setWords(data);
};
// API: useEffect( () => { . . . return cleanup; },[var_n_whose_change_triggers_useEffect . . .] );
useEffect(() => {fetchData()}, [] );
return (
<>
{
words.map(w=> <div>{w.word}</div>)
}
</>
);
}
export default AllWords;
I would like to refactor the fetchData() method out of the component into another file (basically a separate .js file that holds the fetch call).
What I would like is to have created a file titled FetchAllWords.js under src/actions/ & then import it. & use that.
I have several questions :
do I need to set the state in the FetchAllWords.js and then useSelector to extract the state in AllWords.js?
in FetchAllWords.js do I need to usedispatch to dispatch a method call setting the state? I would like to just setState in FetchAllWords.js and then extract it in AllWords.js. This is what I have so far:
import consts from '../constants/Constants.js';
import { useState } from 'react';
async function FetchAllWords(){
const [words, setWords] = useState([]);
const response= await fetch(consts.FETCH_URL);
const data = await (response.json());
setWords(data);
}
export default FetchAllWords;
I am unsure how to import this and use it in AllWords.js. I am using the following statement :
import wordList from '../../actions/FetchAllWords';
Then I am trying to use wordList as a handle to the file '../../actions/FetchAllWords.js' & attempting to access the async function FetchAllWords so wordList.FetchAllWords();
Firstly , the editor (VSCode) won't let me see the function despite the import call.
Secondly I am getting an error (something like) :
TypeError: _actions_FetchAllWords_js__WEBPACK_IMPORTED_MODULE_3__.default.FetchAllWords is not a function
Any insight or help would be appreciated since rather uneasy with JS & React.
The github repo is : https://github.com/mrarthurwhite/hooks-p5-react-redux
EDIT: As per David's suggestions :
So AllWords.js React component is :
import React, { useEffect, useState } from 'react';
import wordList from '../../services/Fetch.js';
function AllWords() {
const [words, setWords] = useState([]);
function fetchData(){
wordList.fetchAllWords().then(
data => setWords(data)
);
};
// API: useEffect( () => { . . . return cleanup; },[var_n_whose_change_triggers_useEffect . . .] );
useEffect(() => {fetchData()}, [] );
return (
<>
{
words.map(w=> <div>{w.word}</div>)
}
</>
);
}
export default AllWords;
And Fetch.js is :
import consts from '../constants/Constants.js';
class Fetch {
async fetchAllWords(){
const response= await fetch(consts.FETCH_URL);
const data = await (response.json());
return data;
}
}
export default Fetch;
No, don't worry about state in the external file. Just focus on the one thing it should do, perform the AJAX operation. At its simplest it's just a function, something like:
import consts from '../../constants/Constants.js';
const fetchAllWords = async () => {
const response = await fetch(consts.FETCH_URL);
const data = await (response.json());
return data;
}
export default fetchAllWords;
You can even make it a class which contains this function, if you plan on adding other service operations as well. (Fetch specific word? Find word? etc.) The point is that this does just one thing, provide data. Let the React components handle React state.
Within the component you'd just use that to get your data. Something like:
import React, { useEffect, useState } from 'react';
import fetchAllWords from '../../services/FetchAllWords.js';
function AllWords() {
const [words, setWords] = useState([]);
useEffect(() => {
fetchAllWords().then(w => setWords(w));
}, []);
return (
<>
{
words.map(w=> <div>{w.word}</div>)
}
</>
);
}
export default AllWords;
Overall it's a matter of separating concerns. The service performs the AJAX operation and returns the meaningful data, internally concerned with things like JSON deserialization and whatnot. The React component maintains the state and renders the output, internally concerned with updating state after useEffect runs and whatnot.

Can I use 'useSWR' with the contentful-client to create pagination?

I'm trying to create pagination with nextjs and the useSWR hook.
This is how I've currently done it, and it appears to be working... however I read in the docs that the key passed as the first parameter should be a unique string (usually a URL). I'm just passing the index to fetch the correct data. Will my approach mess up the caching? I'm not sure if I'm doing this correctly?
index.js
import React, { useState } from 'react'
import Page from '../components/page'
export default function IndexPage( ) {
const [pageIndex, setPageIndex] = useState(0)
return (
<div>
<Page index={pageIndex} />
<button onClick={() => setPageIndex(pageIndex - 1)}>Previous</button>
<button onClick={() => setPageIndex(pageIndex + 1)}>Next</button>
</div>
)
}
And in my page.js
import useSWR from 'swr'
import { fetcher } from '../client/fetcher'
function Page({ index }) {
const { data } = useSWR(index, fetcher)
console.table(data)
return <div>nothing here, just testing</div>
}
export default Page
And finally the fetcher.js
import client from './contentful-client'
export async function fetcher(pageIndex = 1, limit = 3) {
const data = await client.getEntries({
content_type: 'posts',
skip: pageIndex * limit,
order: '-fields.publishDate',
limit,
})
if (data) {
return data
}
console.log('Something went wrong fetching data')
}
You may want to move the Contentful data fetching logic to the server as to not expose credentials and logic to the browser. This could be done using Next.js API routes.
// pages/api/posts.js
import client from '<path-to>/contentful-client' // Replace with appropriate path to file
export default async function handler(req, res) {
const { pageIndex = 1, limit = 3 } = req.query
const data = await client.getEntries({
content_type: 'posts',
skip: pageIndex * limit,
order: '-fields.publishDate',
limit,
})
res.json(data)
}
You could then refactor the code in your page to make a request against the newly created API route, passing the route URL as the key to useSWR.
import useSWR from 'swr'
const fetcher = (url) => fetch(url).then(res => res.json())
function Page({ index }) {
const { data } = useSWR(`/api/posts?pageIndex=${index}`, fetcher)
console.table(data)
return <div>nothing here, just testing</div>
}
export default Page

How to get getServerSideProps results in my IndexPage?

I don't think the getServerSideProps gets run, I'm just starting out and got no clue how to fix this, tried for a few hours but still getting undefined from the IndexPage console.log(props.data)
export default function IndexPage(props) {
console.log(props.data.copyright);
return (
<>
<div>{props.data.copyright}</div>
</>
)
}
export async function getServerSideProps() {
const res = await fetch(" https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY");
const data = await res.json();
return { props: { data } };
}
Edited: the code works perfectly on local machine and vercel deployment, but not on codesandbox.io where I originally started /headache
You have to use a React Hook, and then call the function inside of that. You can then store the response in a state instead
Try something like this:
import fetch from "isomorphic-unfetch";
import React, {useEffect} from "react"
const IndexPage = props => {
console.log(props.data);
if(!props.data){
return <div>Waiting for data...</div>
}
return <div>main page</div>;
};
export async function getServerSideProps() {
const { API_URL } = process.env;
console.log("inside fetch");
const res = await fetch(`${API_URL}/movies`);
const data = await res.json();
return { props: { data } };
}
export default IndexPage;
Otherwise you can use the
getStaticPropsThen ou are ensured, that the data is there, when the component fetches..

Line 105:14: 'accountSelector' is not defined no-undef

Could someone please explain what is going wrong in simple terms so I know how to fix this and can deal with it next time I encounter it.
I have looked through all related questions I could find on stackoverflow and haven't been able to fix it, if I have missed one that answers this then please link it.
I have had this error in the past but usually that was just because I had a typo (e.g. a capital instead of a lowercase) or did not import something correctly however that is not the case this time as far as I can tell.
FIRST CODE app.js
SECOND CODE interactions.js
Here is my code
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import Navbar from './Navbar'
import Web3 from 'web3';
import { connect } from 'react-redux'
// import Token from '../abis/Token.json'
import {
loadWeb3,
loadAccount,
loadToken,
loadExchange
} from '../store/interactions'
class App extends Component {
componentWillMount() {
this.loadBlockchainData(this.props.dispatch)
}
async loadBlockchainData(dispatch) {
const web3 = loadWeb3(dispatch)
const network = await web3.eth.net.getNetworkType()
const networkId = await web3.eth.net.getId()
const accounts = await loadAccount(web3, dispatch) // <<--
const token = loadToken(web3, networkId, dispatch)
loadExchange(web3, networkId, dispatch)
}
// ......................
function mapStateToProps(state) {
return {
account: accountSelector(state)
}
}
export default connect(mapStateToProps)(App);
import Web3 from 'web3'
import {
web3Loaded,
web3AccountLoaded,
tokenLoaded,
exchangeLoaded
} from './actions'
import Token from '../abis/Token.json'
import Exchange from '../abis/Exchange.json'
export const loadWeb3 = (dispatch) => {
const web3 = new Web3(Web3.givenProvider || 'http://localhost:7545')
dispatch(web3Loaded(web3))
return web3
}
export const loadAccount = async (web3, dispatch) => {
const accounts = await web3.eth.getAccounts()
const account = accounts[0]
dispatch(web3AccountLoaded(account))
return account
}
export const loadToken = async (web3, networkId, dispatch) => {
try {
const token = new web3.eth.Contract(Token.abi, Token.networks[networkId].address) // new 이거 의존성(버전) 문제 이거 조심!!!!!
dispatch(tokenLoaded(token))
return token
} catch (error) {
window.alert('Contract not deployed to the current network. Please select another network with Metamask.')
return null
}
}
export const loadExchange = async (web3, networkId, dispatch) => {
try {
const exchange = new web3.eth.Contract(Exchange.abi, Exchange.networks[networkId].address)
dispatch(exchangeLoaded(exchange))
return exchange
} catch (error) {
window.alert('Contract not deployed to the current network. Please select another network with Metamask.')
return null
}
}
i don'k now why this happening to me
but please let me know this problem if you know this issue
The problem seems to be that you do not define or import the accountSelector function anywhere.
You usually define Redux selector functions in your reducer definition files: they take the current Redux store state as argument (and optionally the connected component props) and return the value to be used in your MapStateToProps object property.
Ex.
export const accountSelector = (state) => state.account
You can read more about selectors on the dedicated Redux resources page
replace this
function mapStateToProps(state) {
return {
account: accountSelector(state)
}
}
with this
function mapStateToProps(state) {
return {
account: state.accountSelector
}
}
you are passing complete state in variable instead of accessing.
for your reference, how to access please go through official documentation for your better understanding Redux

React error "./src/App.js Line 7: 'APIKEY' is assigned a value but never used no-unused-vars"

I create a weather app with React.js from tutorial and now I'm stuck and can't solve this error "./src/App.js Line 7: 'APIKEY' is assigned a value but never used no-unused-vars". How can I fix this error?
Below is my code:
import React from 'react';
import './App.css';
import Titles from './components/titles';
import Form from './components/form';
import Weather from './components/weather';
const APIKEY = "0bfdbb5c40aa44b13478951b236a0625";
class WeatherApp extends React.Component {
getWeather = async (e) => {
e.preventDefault();
const api_call= await fetch('http://api.openweathermap.org/data/2.5/forecast?id=524901&APPID={APIKEY}');
const response = await api_call.json();
console.log(response);
}
render() {
return (
<div>
<Titles/>
<Form loadWeather={this.getWeather} />
<Weather/>
</div>
)
}
}
export default WeatherApp;
You can use the template literals.
So :
const api_call= await fetch(`http://api.openweathermap.org/data/2.5/forecast?id=524901&APPID=${APIKEY}`);
With the backtites and the $ sign.

Categories