help... I'm making a project that detects food ingredients using Clarifai API Food model. When the API scans the image, it returns the response via console.log. How do you get THAT output from the API (console.log) and print it in the webpage. sorry, newbie aspiring web dev here.Image of website,console.log, and JS code
Instead of console logging the response, you should define a key value pair in the state of the component:
// the initial value of each key in state should match what data you are storing
this.state = {
input: '',
foodUrl: '',
prediction: {},
};
After the file has received the API response, instead of console logging the response you would write:
this.setState({ prediction: response.outputs[0].data.concepts[0] });
Next you would pass it in to the component you are using to display the response within the render portion of App.js:
<ComponentToRenderAPIResponse prediction={this.state.prediction} />
Within that child component, you would then write something like this within the render portion:
render() {
return (
<div>`Detected Food: ${prediction.name}`</div>
<div>`Prediction Value: ${prediction.value}`</div>
)
}
Instead of storing the entire object displayed in your console, you could just access the name and value key value pairs and store them as separate fields within your state object. Then pass both the name and value as different props to the child component. Also you might want to consider different html tags than the divs I used above as well as adding CSS styling to both tags.
Related
This is my first attempt at building a web app with Vuejs. I've been trying to get data from an external JSON API and display it on my app. The JSON fetch etc is working fine. but I can't get the data to be displayed reactively on my component.
As you can read in Appraisal.js given an API link some data is populated in Appraisal.app_data. The data always has an array called items (that's just how the API is. I'll add validation later). As a proof of concept I'm trying to display the number of elements in the items array.
Since other components in my app will also use this data, I'm using an external store as the data source everywhere. One of the components calls Appraisal.setLink() on getting some user input. That part is working as expected. However the DOM contents don't change at all.
I referred to State Management for setting up the external store. I also referred to some other answers on StackOverflow with a similar issue and got the following suggestions:
The data should be initialized to undefined or null instead of {} for reactivity to work.
Properties of objects are not reactive. But by my understanding this was changed in Vue3 where it doesn't matter because proxies are in use. Either way I tried using the Object.assign({}, ..., ...) method but it did not help.
Arrow functions cannot be used in methods for reactive objects. If I remove the arrow function and put the body inside .then(function(data) {...}) it complains that this is not defined for the second then function on fetch
// --- src/components/AppraisalView.vue
<script setup>
import ItemView from './ItemView.vue';
</script>
<template>
<div v-if="app_data">{{app_data.items.length}} items in appraisal</div>
<div v-else>Enter link to get quote</div>
</template>
<script>
import {Appraisal} from '../stores/Appraisal.js';
export default {
data() {
return {
app_data: Appraisal.app_data,
}
},
}
</script>
// ---- src/store/Appraisal.js
import {reactive} from 'vue'
import {BuybackCalculator} from './BuybackCalculator.js';
export const Appraisal = reactive({
link: '',
app_data: undefined,
methods: {
setLink(value) {
if (this.link == value) return;
this.link = value;
console.log('Updating appraisal with: '+this.link);
fetch(this.link+".json")
.then((response) => response.json())
.then((data) => {
this.app_data = data;
console.log(this.app_data);
BuybackCalculator.methods.calculate_buyback(this.app_data);
});
}
}
});
I have a page in a react app that uses a radio form to filter different objects of data that are being passed to the page.
The problem I am encountering, is that when I change the filter, (click on a different option on the radio form), only some of the data in the resulting list changes. A simple example of what happens is as follows:
Option one is selected with all the old data
Option two is selected, but only some of the new data comes through
First, I use an axios request to get an array of objects that will be used for the data:
componentDidMount() {
axios.get("xxxxxxxxx")
.then(result => {
this.setState({
data: result.data
});
});
Then, I create an array that filters the data from axios by an attribute based on which radio option is selected in the form:
let filteredData = [];
filteredData = this.state.data.filter(thisData => thisData.attribute === "attribute1");
Finally, I map all of the filtered data in the render function:
filteredData.map(filteredItem => ( <MyComponent key={i++} itemInfo={filteredItem.info} /> ))
In the definition of MyComponent, I use props to access the filtered item's info and put it into the table like this:
<td>{this.props.itemInfo.thisDataPoint}</td>
I'd love to hear if anybody has any idea why some of the components data updates when the filter changes, but not all of it. It seems weird to me that some data changes but some does not.
I have tried converting the props into state so that the component re-renders on the change but that did not work.
Thanks again for any help I get :)
given that filteredData is correct, and based on your code the issue must be on key={i++}. using some kind of implementation index can often lead to rendering problems, react will have trouble to distinguish the components since it uses the key to track them.
you should provide some unique identifier to each component as key like key={filteredItem.id}. if you don't have it, you can generate it with some library like uuid.
I have a parent component and ı am making a query to backend in there, then with the help of the navbar and my activeView data in the parent component with on Clicks I render a new child page and pass a prop from my response with the help of v-if in vue. But one of the functions of the method is changing my prop in the parent component also IT CHANGES MY RESPONSE how can this be possible.
This is the before mount of my child component:
beforeMount() {
console.log(this.plansPropOrg);
this.plansProp = this.plansPropOrg;
this.tempPlan = this.plansProp.currentPlan;
console.log(this.plansProp);
this.propsToData();
}
the problematic function is propsToData when ı comment out here it is normal but ı have to call it.
And here is the my parent when ı make the query:
await axios.post("xxxxx/yyyyyyy").then(res => {
console.log("heyyo");
console.log(res);
this.plansData = res.data.data;
console.log(this.plansData);
});
And here is the props to data, it is just translating boolean values to english. But in the response, (when this if is true) ı see the values as translations.
propsToData() {
//TODO: Burdaki if' ifsubscriber olarak değişecel
console.log("AAA");
console.log(this.plansProp);
if (this.plansProp.isSubscriber) {
console.log("BBBBB");
this.plansProp.currentPlan.analytics
? (this.plansProp.currentPlan.analytics = this.$t(
"settings.plans.active"
))
: (this.plansProp.currentPlan.analytics = this.$t(
"settings.plans.inactive"
));
}
}
How can this be possible how can it change the response?
You're copying the response and the plansProp object by reference, meaning both objects are pointing to the same place in memory. When you change one of them, the other still points to the same place in memory, meaning when you retrieve it it's going to be the same object.
You want to do either a shallow (Object.assign()) or a deep (JSON.parse(JSON.stringify())) copy, depending on how your object is structured.
More info on that here https://www.javascripttutorial.net/object/3-ways-to-copy-objects-in-javascript/.
I've been facing a weird issue lately with my React App. I'm trying to parse a JSON object that contains arrays with data. The data is something like this:
{"Place":"San Francisco","Country":"USA", "Author":{"Name":"xyz", "Title":"View from the stars"}, "Year":"2018", "Places":[{"Price":"Free", "Address":"sfo"},{"Price":"$10","Address":"museum"}] }
The data contains multiple arrays like the Author example I've just shown. I have a function that fetches this data from a URL. I'm calling that function in componentDidMount. The function takes the data i.e responseJson and then stores it in an empty array that I've set called result using setState. In my state I have result as result:[]. My code for this would look something like this:
this.setState({result:responseJson})
Now, when I've been trying to access say Author Name from result I get an error. So something like this:
{this.state.result.Author.Name}
I'm doing this in a function that I'm using to display stuff. I'm calling this function in my return of my render function. I get an error stating :
TypeError:Cannot read property 'Name' of undefined. I get the same error if I try for anything that goes a level below inside. If I display {this.state.result.Place} or {this.state.result.Country} it's all good. But if I try,say {this.state.result.Author.Title} or {this.state.result.Places[0].Price} it gives me the same error.
Surprising thing is I've parsed this same object in a different component of mine and got no errors there. Could anyone please explain me why this is happening?
If I store the individual element while I setState in my fetch call function, I can display it. For example:
{result:responseJson,
AuthorName:responseJson.Author.Name
}
Then I'm able to go ahead and use it as {this.state.AuthorName}.
Please help me find a solution to this problem. Thanks in advance!
It could be that your state object is empty on the first render, and only updated with the data from the API after the request has completed (i.e. after the first render). The Name and Place properties don't throw an error, as they probably resolve to undefined.
Try putting an if block in your render method to check if the results have been loaded, and display a loading indicator if they haven't.
I'm guessing your initial state is something like this:
{ results: {} }
It's difficult to say without seeing more code.
[EDIT]: adding notes from chat
Data isn't available on first render. The sequence of events rendering this component looks something like this:
Instantiate component, the initial state is set to { results: [] }
Component is mounted, API call is triggered (note, this asynchronous, and doesn't return data yet)
Render method is called for the 1st time. This happens BEFORE the data is returned from the API request, so the state object is still {results: [] }. Any attempts to get authors at this point will throw an error as results.Authors is undefined
API request returns data, setState call updates state to { results: { name: 'test', author: [...] } }. This will trigger a re-render of the component
Render method is called for the 2nd time. Only at this point do you have data in the state object.
If this state evolves, means it is changed at componentDidMount, or after a fetch or whatever, chances are that your state is first empty, then it fills with your data.
So the reason you are getting this error, is simply that react tries to get this.state.result.Author.Name before this.state.result.Author even exists.
To get it, first test this.state.result.Author, and if indeed there's something there, then get Author.Name like this.
render(){
return(
<div>
{this.state.result.Author ? this.state.result.Author.Name : 'not ready yet'}
</div>
);
}
[EDIT] I'll answer the comment here:
It's just because they are at a higher level in the object.
this.state.result will always return something, even false if there is no result key in your state (no result key in your constructor for instance when the component mounts).
this.state.result.Country will show the same error if result is not a key of your state in your constructor. However, if result is defined in your constructor, then it will be false at first, then become the data when the new state populates.
this.state.result.Author.Name is again one level deeper...
So to avoid it, you would have to define your whole "schema" in the constructor (bad practice in my opinion). This below would throw no error when getting this.state.result.Author.Name if I'm not mistaken. It would first return false, then the value when available.
constructor(props){
super(props);
this.state={
result: {
Author: {}
}
}
}
This is a question about error propagation from react/flux actions into the store and then back to the component, the error is not validation, rather its an api call failure when trying to update the state of the store.
Here is a pretty simple example:
Component:
CityList.jsx
list of cities is held in a field thats bound to store data field, - This loops over these and writes list of City.jsx:
City.jsx
Populates the city data to the user, including a toggle button to say whether they have visited or not, e.g:
name: {this.state.city.name}
country: {this.state.city.country}
visited: {this.state.city.visited}
Toggling the 'visited' button fires a 'toggleVisited' action with that city object:
Actions:
CityActions.js
toggleVisited(city)
Takes a city object, makes a request to the api to update the 'visited' value and pushes result to store
Store:
CityStore.js
onToggleVisited(city)
Receives city object from the action and updates the relevant item in its cities array with new value
Now what happens when the api called in the CityActions returns an error? How do I map that to the correct component to show the appropriate error messages (red border, error text etc) to indicate that the update failed?
My initial thought was to set an error field on the city object after the api call in the action, then set it back in the store looking something like this:
{
name: '',
country: '',
visited: '',
error: true
}
(error could be an object) Then the component would re-render the city and
so then the component could read the error field and show the relevant error messages when its rendered.
So:
Is there a better way to handle these errors?
If I wanted to show a global error at the top of the page, theres no
way to know without looping through the data to check for at least
one instance of {error: true} and then render the error - this is not
ideal.
Is there any way to map errors to components?
To render a global error on top of the page, you could store a global error message in the CityStore.
When the response from the API contains error, you update the global error object in CityStore.
When the view then gets the state from CityStore, you don't need to loop over all cities to check for an error.
You could still keep the error: true in the city object itself, e.g. if you also want to highlight some city in the view that has the actual error.