Vue, fetch returns empty array - javascript

I'm fetching some data in my vue-cli project.
I'm using Vuex to store the data.
It all runs successfully apart from the fact that I get an empty array, I have checked in Postman, and it works perfectly.
As you can see in my actions i had my commit in the if statement, currently commented out and moved. But when run in there I get a Promise returned. And as the current edition of my code I get an empty array.
I really cant see what my error is, so my best bet is you guys are able to see what I'm missing.
First I have my actions:
export default {
async getProLanguages({ commit }) {
commit(C.PROLANGAUGE_DATA_PENDING);
try {
const res = await fetch('https://dev-webapp-kimga5xexrm3o.azurewebsites.net/api/ProLang', {
method: 'GET',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer xxx'
}
});
if (res.status === 200) {
console.log(res);
// commit(C.PROLANGAUGE_DATA_SUCCESS, JSON.stringify(res.json()));
}
else {
commit(C.PROLANGAUGE_DATA_NO_CONTENT);
}
console.log(res)
return commit(C.PROLANGAUGE_DATA_SUCCESS, JSON.stringify(res.json()));
}
catch (e) {
commit(C.PROLANGAUGE_DATA_FAILURE);
}
}
And my mutations:
/**
* Indicates that programming language has succeded
*
* #param state
* #param payload
*/
[C.PROLANGAUGE_DATA_SUCCESS](state, payload) {
state.programmingLanguages = { ...state.programmingLanguages, loading: false, error: false, noContent: false, items: payload }
},
And I have my default state, which is imported into state.js:
const getDefaultState = () => ({
programmingLanguages: {
loading: false,
error: false,
noContent: false,
items: [
{
id: undefined,
name: undefined
}
]
}
});
I call my action with a beforeRouteEnter:
beforeRouteEnter(to, from, next) {
store.dispatch('programmingLanguages/getProLanguages').then(() => {
next();
});
}
and finally in my component I import mapState from Vuex:
computed: {
...mapState({
prolangs: state => state.programmingLanguages.programmingLanguages.items
})
}

I think something like items = await res.json(), then committing items could be a way forward (make sure all promises are resolved).

Related

Dynamic router and page with Next.js and Prisma

I have cards with product information in my database, I display them successfully on the user's page. Now I want to add a more details button on each card to go to a new page from it (/pages/card/[id]). But I don't really understand how I can pull out the card value by clicking through my API.
const res = await fetch('/api/cards/' + id, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ id: id })
})
if (res.ok) {
const result = await (await res).json()
if (result.redirectUrl) {
router.push(result.redirectUrl as string)
}
}
}
API
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { id } = req.query
if (req.method === 'GET') {
if (typeof id === 'string') {
const moreDetail= await db.sales.findUnique({
where: {
id: id },
})
res.send({ redirectUrl: '/card'+[id] })
}
}
My card in schema
id String #id #default(cuid())
title String
description String
active Boolean #default(true)
My suggestion would be to introduce another API endpoint that returns an array of all of the available cards, or at least an array of all of the available card ids. After that, create a new page matching your URL format /pages/card/[id].tsx and inside that file, create your page like normal, but also export 2 functions:
getStaticPaths
getStaticProps
These let Next know what paths are available and how to load data for them during the build process.
export async function getStaticPaths() {
const cardIds = await fetch('/api/cards', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
});
return {
paths: cardIds.map((id) => (
{
params: { id }
},
)),
fallback: false, // setting to false will throw a 404 if none match
};
}
This lets Next know all of the available dynamic routes to generate pages for.
export async function getStaticProps({ params: { id } }) {
const card = await fetch(`/api/cards/${id}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
});
return {
props: {
card,
},
}
}
This actually loads the data from your API given a card id and passes it into your component to display more details for.
Hopefully that gives you a good jumping off point.

Updated object not being returned properly in nextjs

So basically I'm working on a nextjs app which uses authentication. I have a 2 functions which I run on every page load. The first checks if jwt cookies exist and calls another function to validate the tokens if they don't exist. This function is ran from wrapper.getServerSideProps and is passed in the context as ctx. This function works as intended.
export const checkServerSideCookie = (ctx) => {
const access = getCookie("access", ctx.req);
const refresh = getCookie("refresh", ctx.req);
if (access && refresh) {
return checkAuthentication(access, refresh);
} else return { isAuthenticated: false, token: null };
};
The second function is the token validator and this is where the issue arises. I have an object which I intended to update if the validation is successful and leave alone if it isn't. Here is the function
export const checkAuthentication = (access, refresh) => {
const obj = {
isAuthenticated: false,
token: null,
};
const body = JSON.stringify({ token: access });
axios
.post("http://localhost:8000/api/jwtoken/verify/", body, {
headers: {
"Content-Type": "application/json",
},
})
.then((res) => {
obj.isAuthenticated = true;
obj.token = access;
})
.catch((err) => {
// call new token function using refresh
console.log("it doesnt work");
});
return obj;
};
The issue is is that the .then does update the object, and when I console.log(obj) in the .then it shows the proper obj to return, however when I return the obj it still holds the initial values of false and null. I don't understand what the issue is. I try doing the return in the .then itself but it throughs this error
TypeError: Cannot destructure property 'isAuthenticated' of 'Object(...)(...)' as it is undefined.
What is the issue here? It all seems good but the updated obj isn't returned.
axios.post is async, you're returning the obj before it gets filled with data from the api response, you can use async/await to solve that :
export const checkAuthentication = async (access, refresh) => {
const obj = {
isAuthenticated: false,
token: null
};
const body = JSON.stringify({ token: access });
try {
const res = await axios.post("http://localhost:8000/api/jwtoken/verify/", body, {
headers: {
"Content-Type": "application/json"
}
});
obj.isAuthenticated = true;
obj.token = access;
} catch (e) {
// do something with the error
// call new token function using refresh
console.log("it doesnt work");
}
return obj;
};
usage (checkAuthentication now return a promise ) :
checkAuthentication(a, b).then((obj) => {
console.log(obj);
});
When you call checkAuthentication it immediately returns the obj with the default properties. You have an asynchronous operation specified in your function, however you don't wait until it's done. You'd have to rebuild your function the following way:
export const checkAuthentication = (access, refresh) => {
const obj = {
isAuthenticated: false,
token: null,
};
const body = JSON.stringify({ token: access });
return new Promise((resolve, reject) => {
axios
.post("http://localhost:8000/api/jwtoken/verify/", body, {
headers: {
"Content-Type": "application/json",
},
})
.then((res) => {
resolve({
isAuthenticated: true,
token: access
})
})
.catch((err) => {
// call new token function using refresh
console.log("it doesnt work");
reject();
});
});
};
and then call your function the following way:
checkAuthentication(access, refresh)
.then(console.log)
.catch(console.log)
You, of course, have multiple options to make your function cleaner, such as by using async/await etc, but this should give you a quick overview of what is wrong.

ReactJS: Update values without reload the page

I have this problem, when I do a insert or a change about some data, to see the new data I need to reload the page while I would to update automatically the value without the need to reload the page. How can I do?
This is the part where the user click on submit and the post
_onSubmit(Document)
{
const self = this
if ( !_.isEmpty(Document) )
{
//..
if (Document && !_.isEmpty(Document.Anagraphics))
{
alertify.confirm(
utility.t('sureYouWanna_SAVE'),
() => {
const now = new Date();
Document._id = `PRODUCT:${new Date().getTime()}-${utility.CUID()}`
Document.CreationDate = now.toISOString()
Document.CategoryCode
Document.Status = 'New';
Document.Type = 'PRODUCT';
self._POST(Document)
},
function(){}
).set('labels', {ok: utility.t('YES_SAVE'), cancel: utility.t('CANCEL')})
}
else
{
$methods.WarnMissingValues()
}
}
else {
$methods.WarnMissingValues()
}
}
_POST(Document)
{
console.log("DOCUMENT POST", Document)
const self = this
const auth = this.props.db.auth
fetch(`${this.props.db.couch_db_host_url}requests`,{
method: 'POST',
credentials: 'include',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Basic ' + btoa(`${auth.username}:${auth.password}`)
},
body: JSON.stringify(Document)
})
.then(response => {
alertify.dismissAll()
if(response.status > 299 || response.status < 200){
alertify.error(utility.t('AN_ERROR_OCCURRED'))
self._updateState({ submitSucceeded: false })
}
else{
alertify.alert(utility.t('ITEM_EDITED_OK'), function(){})
self.props.history.push({
pathname: RoutesIT.products_details
})
}
})
.catch((err, warning) => {
if (err)
{
alertify.dismissAll()
alertify.error(utility.t('AN_ERROR_OCCURRED'))
console.log('_POST', err);
self._updateState({ submitSucceeded: false })
}
else
{
console.log(warning)
alertify.dismissAll()
alertify.warning(utility.t(warning))
}
})
}
How can I do to not reload the page to see the result of the post? Thank you
UPDATE:
In the page I have also:
function mapStateToProps(state) {
const { app: { login, p, c, l, c_timestamp, p_timestamp, l_timestamp }, form } = state;
return {
db: login ? login.db : null,
Sender: login ? login.Location : null,
timestamp: login ? login.timestamp : null,
[ FORM_NAME ]: form[FORM_NAME],
products: p,
locations: l,
categories: c,
categories_timestamp: c_timestamp,
products_timestamp: p_timestamp,
locations_timestamp: l_timestamp,
utente: login,
};
}
while the reducers
case actions.CATE_UPDATE:
{
return {
...state,
c: action.payload,
c_timestamp: new Date().getTime()
}
}
For what I can see in your code, the problem may lie in the fact that you're not dispatching any action when you submit the data.
Redux store can only be modified via actions, and since you're not triggering any, its contents are never being updated. This explains why your component is not updated in real time: your local data is never changing, so React is not aware of any updates. Things works when you reload the page because you're probably fetching the data from server, where the data did change during your POST request.
In order to fix this issue, you first need to pass a mapDispatchToProp to the your component, same as what you did with mapStateToProps:
connect(mapStateToProps, mapDispatchToProps)(YourComponent);
Inside of mapDispatchToProps, you have to return a property containing a function that will dispatch the CATE_UPDATE action you want to run:
const mapDispatchToProps = (dispatch) => ({
cateUpdateAction: (payload) => dispatch({
type: CATE_UPDATE,
payload
}),
});
Once you've done that, you'll be able to access this function from your component's props and call it inside of your _POST method.
if (response.status > 299 || response.status < 200){
alertify.error(utility.t('AN_ERROR_OCCURRED'))
self._updateState({ submitSucceeded: false })
} else {
alertify.alert(utility.t('ITEM_EDITED_OK'), function(){})
// Dispatch action to update data in Redux store
self.props.cateUpdateAction(data_to_save);
self.props.history.push({
pathname: RoutesIT.products_details
})
}

pass body JSON trough functions to post data axios

After a lot of research at last I found a good way to pass all my updated values of objects though components but I dont find the way to post it with axios. In my code I have a function onChange that brings the updated values from the inputs in another component (or the list of updated objects values) and a function to post, If I send a hardcoded object works just fine, but I cant find the way to sett the updated values from onChange to the actual "updateData" function (the function that make the axios post.
import React, {useState, useEffect} from 'react';
import {CustomFieldsList} from './customFieldsList';
import {toast} from 'react-toastify';
import {ToastInnerDisplay} from '#learnifier/jslib-utils';
import axios from 'axios';
export function CustomFieldsContainer({match}) {
const [value, setValue] = useState({
data: null, // <-- maybe I should pass "newList" here?
loading: true,
error: null,
});
/**
* Initial loading of data.
*/
async function fetchData() {
setValue({...value, error: null, loading: true});
try {
let url = `http://localhost:3000/projectcustomfields.json/list/1741`;
const res = await fetch(url, {
method: 'POST',
mode: 'cors',
withCredentials: true,
credentials: 'include',
});
let data = await res.json();
setValue(prevValue => ({...prevValue, data: data.customFields, loading: false}));
} catch (error) {
toast.error(<ToastInnerDisplay message={error.message} />);
setValue({...value, error, loading: false});
}
}
const updateData = async () => {
console.log(value.data);
let arrOfObj = { // <-- a "hardcoded" objects to update
"items": [
{
"id": 'party',
"value": 'value2new',
},
{
"id": 'goal',
"value": 'value2new2',
}
],
};
try {
await axios({
url: `http://localhost:3000/projectcustomfields.json/updateMany/1741`,
data: arrOfObj, // <-- right now im posting the body JSON avobe declared but I want to pass "newList" variable which I declare on onChange function
method: 'POST',
mode: 'cors',
withCredentials: true,
});
} catch (error) {
toast.error(<ToastInnerDisplay message={error.message} />);
console.log('Error when updating values: ', error);
}
};
const onChange = ({index, updatedValue}) => {
const newList = [...value.data];
const newValue = {...newList[index]};
newValue.value = updatedValue;
newList[index] = newValue;
setValue({
data: newList, //<-- this newList I want to post in upadteData()
loading: false,
error: null,
});
};
useEffect(() => {
fetchData();
}, []);
if (value.loading) {
return <div>loading...</div>;
} else if (value.error) {
return <div>ERROR</div>;
} else {
return (
<div className={'section-component'}>
<div className={'col-md-6 col-sm-12'}>
<h2>Custom Fields</h2>
<CustomFieldsList onChange={onChange} updateData={updateData} list={value.data} />
</div>
</div>
);
}
}
Any help is more than appreciated!
Fixed :) I had to map the items like this:
let arrOfObj = {
items: [...value.data],
};
let postData = [];
arrOfObj.items.map((element, index) => {
postData.push({id: element.id, value: element.value});
});
arrOfObj.items = postData;
and VOILA! doing the job

Why are Relay Modern QueryRenderer render props undefined?

This is my first attempt at using Relay Modern.
Fetching for a specific User from a PostgraphQL GraphQL Server.
It is fetching the data successfully but not passing to render function:
import {createFragmentContainer, QueryRenderer, graphql} from 'react-relay'
import environment from 'environment'
#CSSModules(styles) export default class Profile extends Component {
render() {
var {props: {children}} = this
return (
<QueryRenderer
environment={environment}
query={graphql`
query ProfileQuery {
userById(id: "f0301eaf-55ad-46db-ac90-b52d6138489e") {
firstName
userName
}
}
`}
render={({error, relayProps}) => {
if (error) {
return <div>{error.message}</div>
} else if (relayProps) {
...
}
return <div>Loading...</div>
}}
/>
)
}
}
Only "Loading..." is rendered.
I am guessing because it successfully fetches data that the graphql server and environment are ok.
I am not using React 16 and the project also uses Redux.
Any suggestions please as to why relayProps wouldn't have a value (e.g. relayProps.user)?
One further thing that may help, the environment (file) is in the main application and the QueryRenderer and components are in an imported npm package (to be shared across a number of applications). As mentioned, the query seems to work fine so I did not think this was a problem. I also run the relay compiler on the package but not the main application since there are no relay components there.
Just in case it's needed the environment is setup using:
const {
Environment,
Network,
RecordSource,
Store,
} = require('relay-runtime')
// Instantiate Store for Cached Data
const store = new Store(new RecordSource())
// Create Network for GraphQL Server
const network = Network.create((operation, variables) => {
// GraphQL Endpoint
return fetch(config.gqlapiProtocol + "://" + config.gqlapiHost + config.gqlapiUri + "/a3/graphql" , {
method: 'POST',
headers: {
'Content-Type': "application/json",
'Accept': 'application/json',
},
body: JSON.stringify({
query: operation.text,
variables,
}),
}).then(response => {
return response.json()
})
})
// Instantiate Environment
const environment = new Environment({
network,
store,
})
// Export environment
export default environment
props are not relayprops
render={({ error, props }) => {
if (error) {
return <div>{error.message}</div>;
} else if (props) {
...
}
return <div>Loading...</div>;
}}
and
fetch(GRAPHQL_URL, {
method: 'POST',
get headers() {
return {
'Content-Type': 'application/json',
'Accept': 'application/json',
};
},
body: JSON.stringify({
query: operation.text, // GraphQL text from input
variables
})
})
.then(response => response.json())
.then((json) => {
// https://github.com/facebook/relay/issues/1816
if (operation.query.operation === 'mutation' && json.errors) {
return Promise.reject(json);
}
return Promise.resolve(json);
})
);

Categories

Resources