So I have this Product.js component that fetches data from my backend data. I'm trying get this component to upload JSX code by using the data I fetched. However, when the server finishes my component just returns the div and not the data within it. Here's the code:
import React , {useState, useEffect} from 'react';
import { useParams } from 'react-router-dom';
import "./popup.css"
function Product(){
const [user, setUser] = useState();
const params = useParams()
console.log(params);
async function getUser(id) {
const response = await fetch(`http://localhost:8000/cats/${id}`)
const data = await response.json();
console.log(data);
setUser(params.id);
}
useEffect (() => {
getUser(params.id);
},[params.id])
document.body.style ='#bacdd8';
if(user){
return(
<div className='container'>
<div className='images'>
<img src={user.image_url} alt={user.name} />
</div>
<div className='cat'>
<h1>{user.name}</h1>
<p className='desc'>{user.description}</p>
</div>
</div>
)
}else{
<p>Still Loading...</p>
}
}
export default Product;
The code above shows what I've tried which was to just use an if statement to wait for the user to pick up something then return the JSX but apparently it doesn't in time. The only proof I have that it loads is when it shows on the console. However, my conclusion is that the JSX is just loading before the data. How can I fix this?
I think this is just a typo on your part. You should be setting the user to the data you got from the server and not the params id.
async function getUser(id) {
const response = await fetch(`http://localhost:8000/cats/${id}`)
const data = await response.json();
console.log(data);
setUser(params.id); <-----------------
}
I'm doing the youtube tutorial "ECommerce Web Shop - Build & Deploy an Amazing App | React.js, Commerce.js, Stripe" and this error appeared when I was sending a new product object from the Commerce.js. (minute 45:50)
I have the corresponding code:
import React, {useState, useEffect } from 'react';
import { commerce } from './lib/commerce'
import {Products, Navbar } from './components'
// to create a full function web shell app, we need a
// full api that is stored on commerce import
const App = () => {
//new state
const [products, setProducts] = useState([]);
// fetch data from the commerce instance
// fetch the products immediatelly on the aplication load
const fetchProducts = async () => {
// this is going to return a promise that we have to
// await to see what is inside of that promise
const { data } = await commerce.products.list();
// now the products are going to be populated
setProducts(data);
}
/* this is to call the fetch product function and set
products to the state, the empty list means that it's
only going to render at the start */
useEffect(() => {
fetchProducts();
},[]);
console.log(products);
return (
<div>
<Navbar/>
<Products/>
</div>
);
}
export default App;
[It should have printed the object on the console, but instead I have the error]
(Error)
https://i.stack.imgur.com/Symbp.png
Im using NextJS/Redux Toolkit for e-commerce. I try to get the token in pre-render, the dispatch is working I can access the data in my page using props from getStaticProp but when using useSelector return no value why? But then I call the thunk in my useEffect in client, useSelector is working fine.
export const getStaticProps: GetStaticProps = async () => {
const data = await appStore.dispatch(
loginThunks.login.loginAsGuest({
url: process.env.NEXT_PUBLIC_API,
tenantId: 99,
})
);
return {
props: { data },
};
};
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
Built API with NodeJS, Express & MongoDB, used JWT and Cookies for user authentication.
Fetched user data from API with axios service using store (vuex). Created auth.js in store folder, created fetchData action which GETs the data from backend (axios.get(apiRoute)) and sets the user to state.
Wanted to do this using nuxtServerInit, so i craeted index.js file in store folder. Added empty state & actions. Action containts nuxtServerInit which uses dispatch() to call fetchData method in auth.js.
Yet after all of this, it doesn't work at all. For example: User is logged in, but account page is not rendering with user data (name, email, image etc.).
I tried returning a promise from fetchData action in auth.js, and it didn't work.
Also i tried setting up fetchData action insite of the index.js file and calling dispatch directly on it.
store/auth.js
// Importing Files
import axios from 'axios';
// State
export const state = () => ({
user: null
});
// Mutations
export const mutations = {
SET_USER (store, data) {
store.user = data
},
RESET_USER (store) {
store.user = null
}
};
// Actions
export const actions = {
// Fetch User Account
async fetchData ({ commit }) {
try {
const response = await axios.get('http://localhost:3000/api/v1/users/account');
commit('SET_USER', response.data.doc);
return response;
} catch (err) {
commit('RESET_USER');
}
}
};
store/index.js
// State
export const state = () => ({
});
// Actions
export const actions = {
async nuxtServerInit({ dispatch }) {
console.log('Testing');
const res = dispatch('auth/fetchData');
return res;
}
};
components/Settings.vue
<template>
<section class="data-block-wrap" v-if="user">
<BlockHeader :blockHeaderName="`Welcome Back, ${user.name.split(' ')[0]}`" btnText="More Details" />
<img :src="getPhotoUrl(user.photo)" alt="User Photo" class="user-data__image">
<p class="user-data__short-bio">{{ user.shortBio }}</p>
</section>
</template>
<script>
export default {
// Computed
computed: {
user() {
return this.$store.state.auth.user;
}
}
...
};
</script>
I expect to render user data properly on Vue components but currently it doesn't work at all. The render is static, no data from database / api showing.
EDIT / UPDATE
App renders user data properly when calling fetchData on created() hook in default.vue file ('Parent' file for all of the components).
default.vue
<template>
<div class="container">
<TopNav />
<SideNav />
<nuxt />
</div>
</template>
// Importing Components
import TopNav from '#/components/navigation/TopNav';
import SideNav from '#/components/navigation/SideNav';
import axios from 'axios';
import { mapActions } from 'vuex';
export default {
components: {
TopNav,
SideNav
},
methods: {
// Map Actions
...mapActions('auth', ['fetchData']),
async checkUser() {
const user = await this.fetchData();
},
},
// Lifecycle Method - Created
created() {
this.checkUser();
}
}
</script>
It seems that something very interesting is happening here. The problem is calling axios.get('http://localhost:3000/api/v1/users/account') from within nuxtServerInit().
This is causing what is essentially an infinite recursion. nuxtServerInit makes a call to http://localhost:3000, which hits the same server, runs nuxtServerInit again, and calls http://localhost:3000, and so on until the javascript heap is out of memory.
Instead of using nuxtServerInit for this, use the fetch method:
The fetch method is used to fill the store before rendering the page,
it's like the asyncData method except it doesn't set the component
data.
Note: You do not have access to the Nuxt component in fetch, so you must use the context object instead of "this"
// inside your page component
export default {
fetch (context) {
return context.store.dispatch('auth/fetchData');
}
}
As a general rule:
Use fetch to fill store data on the server or client
Use asyncData to fill component data on the server or client
Use nuxtServerInit for things like setting up the store with values on the request object, like sessions, headers, cookies, etc, which is only required server side
The solution to this question is to use the NuxtServerInt Action this way inside your store.js
1. you will need to run npm install cookieparser and npm install js-cookie
const cookieparser = process.server ? require('cookieparser') : undefined
export const state = () => {
return {
auth: null,
}
}
export const mutations = {
SET_AUTH(state, auth) {
state.auth = auth
},
}
export const actions = {
nuxtServerInit({ commit }, { req }) {
let auth = null
if (req.headers.cookie) {
try {
const parsed = cookieparser.parse(req.headers.cookie)
auth = parsed.auth
} catch (err) {
console.log('error', err)
}
}
commit('SET_AUTH', auth)
},
}
Then in your login page component, you call your backend API, just like this
import AuthServices from '#/ApiServices/AuthServices.js'
import swal from 'sweetalert'
const Cookie = process.client ? require('js-cookie') : undefined
async onSubmit() {
try {
const body = {
email: this.email,
password: this.password,
}
const res = await AuthServices.loginUrl(body)
console.log('res', res)
console.log('res', res.data.message)
setTimeout(() => {
// we simulate the async request with timeout.
const auth = {
accessToken: res.data.payload.token, // from your api call, you get the user token
userData: res.data.payload.user,
}
swal('Logged in', `${res.data.message}`, 'success')
this.email = this.password = ''
this.$refs.loginForm.reset()
this.$store.commit('setAuth', auth) // mutating to store for client rendering
Cookie.set('auth', auth) // saving token in cookie for server rendering
this.$router.push('/')
}, 1000)
} catch (error) {
console.log('error', error)
swal('Error!', `${error.message}`, 'error')
}
},
your AuthServices.js looks like this
import axios from 'axios'
const apiClient = axios.create({
baseURL: `http://localhost:3000`,
})
export default {
loginUrl(body) {
return apiClient.post('/login', body, {
headers: {
'Content-Type': 'application/json',
},
})
}
}
then you get the user data using computed in the navbar or say dashboard e.g to say Hi,Xavier
inside where you want place the user data, just add this
<template>
<section>
<p class="firtname_data">Hi, {{ user.firstnam }}</p>
</section>
</template>
<script>
export default {
// Computed
computed: {
user() {
return this.$store.state.auth.userData
}
...
};
</script>
Hope this help... it worked for me
I think you forgot to write await before dispatch
export const actions = {
async nuxtServerInit({ dispatch }) {
console.log('Testing');
const res = await dispatch('auth/fetchData');
return res;
}
}