Filtering a JSON response with Vue - javascript

I'm practicing using axios with Vue, but I think this may be more of a general JSON question.
I've successfully used axios to get my local products.json file and I'm then using filter to create a new array that only has products that have a matching department property, and looping those out.
Is this the correct way of doing this, or can I actually filter the JSON result on the original axios call? I understand I can to pass a parameter which will in turn perform a specific database call, and only provide the required JSON in the first place.
data(){
return {
products: []
}
},
components: {
Product
},
computed: {
foodProducts(){
return this.products.filter(x => x.department == 'Food')
}
},
mounted() {
axios
.get('./json/products.json')
.then(response => (this.products = response.data.products))
}
Thanks. Just trying to clarify the theory behind it.

It works in many ways depending on your situation or requirement.
Your way works. Alternatively, you can also filter the result directly from the API call assuming that the backend is returning a full result.
data() {
return {
filteredProducts: []
}
}
mounted() {
axios.get(API_URL)
.then(response => {
const products = response.data
this.filteredProducts = products.filter(product => product.department.includes('food'))
})
}

If you're querying the products list from a Back-end server,
you may use query parameters like
xxx/products?department=XXX
then the backend server can do the filtering for you.
In your case, it looks like you are simply reading a local JSON file, so the entire JSON is returned, and you have to filter yourself.

Related

Filtering objects after API call

I am having trouble showing the results after filtering the data received form API call, my guess is it is trying to filter the data before it has received it, and that is why it isn't showing. I have only managed to get the data by setting filterAnswers() to setTimeout function, but it loops continuously until it breaks. any idea how I can filter only the correct_answers and save it to state?
const [quiz, setQuiz] = React.useState([])
const [correctAnswers, setCorrectAnswers] = React.useState(filterAnswers())
React.useEffect(() => {
fetch("https://opentdb.com/api.php?amount=5&difficulty=medium&type=multiple")
.then(res => res.json())
.then(data => setQuiz(data.results))
}, [])
console.log(quiz)
function filterAnswers() {
let filter = []
quiz.forEach((question) => {
filter.push(decode(question.correct_answer));
})
return filter
console.log(correctAnswers)
};
my guess is it is trying to filter the data before it has received it
Indeed, the code is explicitly doing exactly that:
const [correctAnswers, setCorrectAnswers] = React.useState(filterAnswers())
You could invoke your "filter" logic when receiving the data, instead of immediately upon loading the component. First, change the function to no longer depend on state:
function filterAnswers(questions) {
let filter = [];
questions.forEach((question) => {
filter.push(decode(question.correct_answer));
})
return filter;
};
Then invoke it when you receive your data:
fetch("https://opentdb.com/api.php?amount=5&difficulty=medium&type=multiple")
.then(res => res.json())
.then(data => {
setQuiz(data.results);
setCorrectAnswers(filterAnswers(data.results));
})
Then of course the default initial state for correctAnswers would just be an empty array, exactly like it is for quiz:
const [correctAnswers, setCorrectAnswers] = React.useState([])
As an aside, it's worth noting that you're somewhat duplicating state here. Unless this filter/decode process is very expensive, it might be better to do this directly when calculating or display data rather than store it as state. Since this "correct answers" data is derived from the "quiz" data, by keeping both in state separately you also will need to keep that data synchronized. Changes to one need to be made in the other.
That might not become a problem with the functionality you're currently building, but it's something to keep in mind.

Unpack nested JSON in Next.js

I am attempting to unpack nested JSON via a fetch function I created. But, I am unsure how to get a specific array, for example pull the 'date' from index of 1. Currently, this is what I have:
Home.getInitialProps = async function() {
const res = await fetch('https://api.covidtracking.com/v1/us/daily.json')
const data = await res.json()
return {
//Obviously this is providing me with an error
data[1].date
}
}
My JSON:
[{"date":20210112}, {"date":20210111}, {"date":202101131}]
What is the correct way to do this, and subsequently get the values inside of the array?
try this
return {
date: data[0]['date']
}
If you're using Next.js 9.3 or newer, we recommend that you use
getStaticProps or getServerSideProps instead of getInitialProps.
https://nextjs.org/docs/api-reference/data-fetching/getInitialProps

Vue Array converted to Proxy object

I'm new to Vue. While making this component I got stuck here.
I'm making an AJAX request to an API that returns an array using this code:
<script>
import axios from 'axios';
export default {
data() {
return {
tickets: [],
};
},
methods: {
getTickets() {
axios.get(url)
.then((response) => {
console.log(response.data) //[{}, {}, {}]
this.tickets = [...response.data]
console.log(this.tickets) //proxy object
})
},
},
created() {
this.getTickets();
}
};
</script>
The problem is, this.tickets gets set to a Proxy object instead of the Array I'm getting from the API.
What am I doing wrong here?
Items in data like your tickets are made into observable objects. This is to allow reactivity (automatically re-rendering the UI and other features). This is expected and the returned object should behave just like the array.
Check out the reactivity docs because you need to interact with arrays in a specific pattern or it will not update on the ui: https://v3.vuejs.org/guide/reactivity-fundamentals.html
If you do not want to have reactivity - maybe you never update tickets on the client and just want to display them - you can use Object.freeze() on response.data;
if you want reactive information use toRaw
https://vuejs.org/api/reactivity-advanced.html#toraw
const foo = {}
const reactiveFoo = reactive(foo)
console.log(toRaw(reactiveFoo) === foo) // true
or use unref if you donot want ref wrapper around your info
https://vuejs.org/api/reactivity-utilities.html#unref
You can retrieve the Array response object from the returned Proxy by converting it to a JSON string and back into an Array like so:
console.log(JSON.parse(JSON.stringify(this.tickets)));
You're not doing anything wrong. You're just finding out some of the intricacies of using vue 3.
Mostly you can work with the proxied array-object just like you would with the original. However the docs do state:
The use of Proxy does introduce a new caveat to be aware of: the proxied object is not equal to the original object in terms of identity comparison (===).
Other operations that rely on strict equality comparisons can also be impacted, such as .includes() or .indexOf().
The advice in docs doesn't quite cover these cases yet. I found I could get .includes() to work when checking against Object.values(array). (thanks to #adamStarrh in the comments).
import { isProxy, toRaw } from 'vue';
let rawData = someData;
if (isProxy(someData)){
rawData = toRaw(someData)
}

Storing JSON structure in VueX

I'm fairly new to Vue/VueX, and I'm researching a solution to store JSONs in the VueX state. At first it seems pretty straightforward:
state {
jsonthing: { ... }
}
The problem: getters return Observer type, not Object type. So I can do this and retrieve the entire JSON structure:
getters: {
getJSON(state) {
return state.jsonthing;
}
}
But I can't retrieve a node or a single value of the JSON, like this:
getters: {
getOneNode: state =>
nodeName => {
return state.jsonthing[nodeName];
}
}
}
The getter retrieves state.jsonthing as an Observer. I can't find a way to extract the desired content of the JSON from this Observer and return that. I know I can do it in my components using mapState but that's not what I'm looking for. Is there a way to do it in the getter?
What I'm currently doing is that I store the JSON as a string (JSON.stringify()) and convert it back in the getter (JSON.parse()). Strings are retrieved as strings, and not Observers. It works, but it's a hack.
While we are here, I also can't find any documentation for the Observer type. I'd appreciate if someone could drop a URL!
All right guys, you're not very active today, so here is a solution. If you know a better one, please let me know.
Solution 1:
Convert the JSON into a string with JSON.stringify() and store it as a string. Then the getter converts it back with JSON.parse(). This works, but admittedly ugly.
Solution 2:
Generate a function that returns the JSON. This is way better.
state: {
jsonthing: null
}
mutations: {
INITIALIZE(state, jsonthing) {
state.jsonthing = new Function(`return ${ JSON.stringify(jsonthing) }`)
}
}
getters: {
getOneNode: state =>
nodeName => {
return state.jsonthing()[nodeName];
}
}
}
I've written an article on Medium about this method and a practical application (which I'm actually implementing).
https://medium.com/developer-rants/simple-dynamic-localization-in-vue-with-vuex-b429c525cd90

Javascript fetch API in react-flux

I am studying the flux-react-router-example by #Dan Abramov, I notice in the Fetch API code here: The fetch API has a return promise that has a nested return inside:
return fetch(url).then(response =>
response.json().then(json => {
const camelizedJson = camelizeKeys(json);
const nextPageUrl = getNextPageUrl(response) || undefined;
return {
...normalize(camelizedJson, schema),
nextPageUrl
};
})
);
I am confused with this nested returns, why is this used here? Why not just return response.json()?
Seems like if I do the same thing, I will get a undefined value
The json retrieved from the response is
converted to camelCase using humps
un-nested using normalizr for easier handling in combination with the redux store
enriched with the next page url, parsed from the link header
More discussion and reasoning about why storing nested response objects in the store is usually a bad idea can be found at the React JS Google Group.

Categories

Resources