React Native how to setState data inside data? - javascript

For example:
We have in the constructor the avatar data, inside the avatar there is thumb and inside the thumb the url. I just want to get the url. anyone has any hint to spare?
{avatar: {:thumb{:url}}}
constructor(props) {
super(props);
this.state = {
id: "",
avatar: "",
bio: "",
error: "",
}
}
fetched user data
async fetchUserId() {
let auth_token = await AsyncStorage.getItem(AUTH_TOKEN);
fetch("https://xxx.herokuapp.com/api/users/"+auth_token+"", {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
}).then((response) => response.json())
.then((json) => {
this.state.id = json.id
//this.state.url = json.avatar.thumb.url
})
.catch((error) => {
console.error(error);
});
}

Update:
you're not setting json.id and json.avatar correctly to the state you need to use setState
this.setState({ id: json.id,avatar: json.avatar })
Solution one
constructor(props) {
super(props);
this.state = {
id: "",
avatar: {},
bio: "",
error: "",
url: ""
}
}
getUrl = () =>{
if(this.state.avatar && this.state.avatar.thumb && this.state.avatar.thumb.url){
this.setState({ url: this.state.avatar.thumb.url })
}
}
<button onClick={this.getUrl}>Get URL </button>
Solution Two
Because avatar is coming from async I suggest you to use componentWillUpdate lifecycle method
componentWillUpdate(nextProps, nextState){
if(this.state.avatar !== nextState.avatar){
console.log(nextState.avatar.thumb.url)
}
}
Note: componentWillUpdate will invoket on everytime that this.state.avatar changes

Since you cannot mutate the state, and since setState doesn't handle nested updates, you need to use the following code to set such a state:
this.setState(prevState => ({
...prevState,
avatar: {
...prevState.avatar,
thumb: {
...prevState.avatar.thumb,
url: newUrlValue
}
}
}))

Like This You can set:-
class App extends Component {
state = {
name: "",
stars: "",
icon: "",
longitude: "",
address:"",
latitude: "",
trails: [], isLoaded: false
}
handleChange = address => {
this.setState({
address
});
geocodeByAddress(address)
.then(res => getLatLng(res[0]))
.then(({ lat, lng }) => {
this.setState({
latitude: lat,
longitude: lng,
});
})
.catch(error => {
this.setState({ isGeocoding: false });
console.log('error', error); // eslint-disable-line no-console
});
}
getUser = selected => {
var object = this.refs.Progress2;
object.innerHTML="";
this.setState({ isGeocoding: true, address: selected });

Related

Clarifai API not detecting the image URL in React.js

I am using Clarifai API face detection and it is unable to fetch the URL which is provided from the constructor, rather than a variable which Clarifai provides in the default code
class App extends Component{
constructor(){
super();
this.state = {
input : '',
IMAGE_URL: '',
}
}
onInputChange = (event) =>{
this.setState({input: event.target.value});
}
onSubmit = () =>{
this.setState({IMAGE_URL : this.state.input});
const raw = JSON.stringify({
"user_app_id": {
"user_id": USER_ID,
"app_id": APP_ID
},
"inputs": [
{
"data": {
"image": {
"url": this.state.IMAGE_URL
}
}
}
]
});
const requestOptions = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Authorization': 'Key ' + PAT
},
body: raw
};
// NOTE: MODEL_VERSION_ID is optional, you can also call prediction with the MODEL_ID only
// https://api.clarifai.com/v2/models/{YOUR_MODEL_ID}/outputs
// this will default to the latest version_id
fetch("https://api.clarifai.com/v2/models/" + MODEL_ID + "/versions/" + MODEL_VERSION_ID + "/outputs", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
}
I started facing this issue when I added IMAGE_URL in constructor to update it from my input form on the webpage.
It works fine if i move IMAGE_URL out from the constructor and making it a variable and hard code the image url in the editor
Edit:
This is the code after some tweaks. Still same error
onInputChange = (event) =>{
this.setState({input: event.target.value});
console.log(typeof(input),'TYPE OF INPUT');
var inp = this.state.input;
return inp
//console.log(inp);
console.log(typeof(inp)); //it is string here
}
onSubmit = () =>{
this.setState({IMAGE_URL : this.state.inp});
const raw = JSON.stringify({
"user_app_id": {
"user_id": USER_ID,
"app_id": APP_ID
},
"inputs": [
{
"data": {
"image": {
"url": this.state.IMAGE_URL
}
}
}
]
Edit 2:
It's working now and I guess I broke some rules. I have declared a global variable and passed the value of the input field to it and then used it in my API.
var inp = ''; //THIS IS THE NEW VARIABLE
class App extends Component{
constructor(){
super();
this.state = {
input : '',
IMAGE_URL: '',
}
}
onInputChange = (event) =>{
this.setState({input: event.target.value});
inp = event.target.value;
console.log(inp);
return inp;
}
onSubmit = () =>{
console.log('*********',inp,'***********');
this.setState({IMAGE_URL : this.state.input});
const raw = JSON.stringify({
"user_app_id": {
"user_id": USER_ID,
"app_id": APP_ID
},
"inputs": [
{
"data": {
"image": {
"url": inp
}
}
}
]
Seems like you've found a workaround with a global variable; but I think the actual problem was with:
this.setState({IMAGE_URL : this.state.input});
in the onSubmit function.
The setState function in react:
Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass.
https://reactjs.org/docs/react-component.html#setstate
So basically you're making a request to update that variable (IMAGE_URL) and then immediately using it. Since React is trying to optimize writes, you are trying to use it before it is actually updated. You can request that update and then use the already populated version if you want.
I think the following code should work and allow you to keep out of the global scope (if that bothers you).
class App extends Component{
constructor(){
super();
this.state = {
input : '',
IMAGE_URL: '',
}
}
onInputChange = (event) =>{
this.setState({input: event.target.value});
}
onSubmit = () =>{
// This may not trigger right away, but if you want to transfer the this.state.input to this.state.IMAGE_URL it _eventually_ will
this.setState({IMAGE_URL : this.state.input});
const raw = JSON.stringify({
"user_app_id": {
"user_id": USER_ID,
"app_id": APP_ID
},
"inputs": [
{
"data": {
"image": {
"url": this.state.input
}
}
}
]
});
const requestOptions = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Authorization': 'Key ' + PAT
},
body: raw
};
// NOTE: MODEL_VERSION_ID is optional, you can also call prediction with the MODEL_ID only
// https://api.clarifai.com/v2/models/{YOUR_MODEL_ID}/outputs
// this will default to the latest version_id
fetch("https://api.clarifai.com/v2/models/" + MODEL_ID + "/versions/" + MODEL_VERSION_ID + "/outputs", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
}

How do I setState for a nested object in React?

I'm learning react by building a weather api. I make an API call and store it in state.
state = {
forecasts: {
error: null,
isLoaded: false,
forecasts: []
}
}
componentDidMount() {
const endpoint = `http://dataservice.accuweather.com/forecasts/v1/daily/5day/207931?apikey=KEY&language=en&details=true&metric=true`;
fetch(endpoint)
.then(res => res.json())
.then((result) => {
this.setState({
'forecasts.isLoaded': true,
'forecasts.forecasts': result.DailyForecasts,
});
},
(error) => {
this.setState({
'forecasts.isLoaded': true,
'forecasts.error': error
});
})
}
When I pass this down as props, I get no data?
<WeatherOverview weather={this.state.forecasts}/>
Use spread syntax to copy the entire previous object and then override some of its keys. You should also use the form of setState that takes a function because you want to reference the previous value of state.forecasts:
.then((result) => {
this.setState(state => ({
forecasts: {
...state.forecasts,
isLoaded: true,
forecasts: result.DailyForecasts,
},
}));
},
(error) => {
this.setState(state => ({
forecasts: {
...state.forecasts,
isLoaded: true,
error: error,
},
}));
})
or you may want entirely new objects to wipe out the previous error state:
.then((result) => {
this.setState({
forecasts: {
error: null,
isLoaded: true,
forecasts: result.DailyForecasts,
},
});
},
(error) => {
this.setState(state => ({
forecasts: {
forecasts: [],
isLoaded: true,
error: error,
},
}));
})
you are not passing the state correctly, you need to pass the state without quotation marks
this.setState({
'forecasts.isLoaded': true,
'forecasts.forecasts': result.DailyForecasts,
});
should be like this:
this.setState({
forecasts: {
...state.forecasts,
isLoaded:true,
forecasts:result.DailyForecasts},
});

React - Loading data before render

I'm new to react and I have a question about a best practice that sees me make a mistake .
I call an API to retrieve information and modify an array in the state once the response is returned by the API. In the "render" I have to retrieve the information from this array (when it is completed) or it sends me back an error because the array is empty when the render is initialized.
class MyClass extends React.Component {
constructor(props) {
super(props)
this.state = {
activeIndex: 0,
items: []
}
}
componentDidMount() {
axios
.get(`API_ADDRESS`, {
headers: {
Authorization: `Token XXX`,
},
})
.then(function(response) {
this.setState({
items: response.results,
})
})
.catch(error => {
notification.warning({
message: error.code,
description: error.message,
})
})
}
changeDialog = (e, index) => {
e.preventDefault()
this.setState({
activeIndex: index,
})
}
render() {
const { activeIndex, items } = this.state
const {
first_name: firstName,
last_name: lastName,
phone,
email,
address,
} = items[activeIndex]
The error indicates :
TypeError: _items$activeInde is undefined
How can I solve this error related to data loading? (trying to keep the destrying elements method)
Thanks a lot
Eliott
Because API that you fetch from server is async. The first time render of Component, data that you setState in axios still not yet updated, it just updated when Component render the second time.
So you must check state in render Component like this to make sure that if activeIndex is defined then declare variable with items[activeIndex] :
activeIndex && const {
first_name: firstName,
last_name: lastName,
phone,
email,
address,
} = items[activeIndex]
Two issues:
beware of this inside the Promise returned by axios. You use function(){} so the this inside is not the component's instance. Change it to an arrow function.
add a guard so you won't destructure undefined when activeIndex points to an item element that is not there (which happens in the initial loading before the axios fetches the data).
Fix:
// ... (code not shown remains unmodified)
componentDidMount() {
axios
.get(`API_ADDRESS`, {
headers: {
Authorization: `Token XXX`,
},
})
.then(response => { // changed this line
this.setState({
items: response.results,
})
})
// ... (code not shown remains unmodified)
render() {
const { activeIndex, items } = this.state
if (!items[activeIndex]) { // added this line
return <div>Hold tight while items are being fetched...</div>; // added this line
} // added this line
const {
first_name: firstName,
// ... (code not shown remains unmodified)
just change your component like so:
constructor(props) {
super(props)
this.state = {
activeIndex: 0,
items: [],
isFetching: false
}
}
componentDidMount() {
// staring your fetching
this.setState({isFetching: true});
axios
.get(`API_ADDRESS`, {
headers: {
Authorization: `Token XXX`,
},
})
.then(function(response) {
// finish fetching when your response is ready :)
this.setState({
items: response.results,
isFetching: false
});
})
.catch(error => {
// finish fetchnig
this.setState({isFetching: false})
notification.warning({
message: error.code,
description: error.message,
})
})
}
changeDialog = (e, index) => {
e.preventDefault()
this.setState({
activeIndex: index,
})
}
render() {
// if your component is while fetching shows a loading to the user
if(this.state.isFetching) return <div>Loading...</div>;
// if there is no results shows a msg to the user
if(this.state.items.length === 0) return <div>there is not items!!!</div>
const { activeIndex, items } = this.state
const {
first_name: firstName,
last_name: lastName,
phone,
email,
address,
} = items[activeIndex]

Having issue with state variable in react js. Cannot update the variable's value to true

import getAuthentication from './getAuthentication';
class Home extends React. Component {
constructor() {
super();
//this.authentication = false;
this.state = {
username: '',
password: '',
check:false,
authentication:false
};
this.err = '';
}
componentDidUpdate() {
console.log (this.state.authentication);
console.log(this.state.authentication == true);
if (this.state.check)
{
const promiseAuthentication = getAuthentication(
this.state.username,
this.state.password,
);
promiseAuthentication
.then(response => {
console.log (response.data.Success);
console.log(response.data.Success == true);
this.setState({check :false, authentication:response.data.Success});
})
.catch(error => {
// console.log(error);
this.err = error;
});
}
if (this.state.authentication == true) {
event.preventDefault();
history.push('/overview');
}
}
assignUsername = event => {
this.setState({ username: event.target.value });
};
assignPassword = event => {
this.setState({ password: event.target.value });
};
handleSubmit = () => {
this.setState({ check:true });
};
==============================================================
getAuthentication.js
import axios from 'axios';
function getAuthentication(username, password) {
const authenticationConfig = {
Email: username,
Password: password,
};
return axios.post(
'http://localhost:5002/login/confirmation',
authenticationConfig,
);
}
export default getAuthentication;
In the above code my this.state.Authentication is not getting updated to true
I am trying to update its value in axios promise.
Can someone please tell me what's wrong? I mean I have tried everything but I am not able to proceed.
How do I change the state of Authentication object and switch new window?
I have a second file that is returning the axios promise where promise value is "undefined".. How do I make async call and resolve this issue ??
componentDidUpdate is wrapped in if (this.state.check). Nothing in the code you pasted sets this.state.check to true. Set this.state.check: true.

React how to render async data from api?

I am using preact(light version of react) but syntax is almost the same. I am having an issue displaying verified after setting state from promise result. This is my container component:
import { h, Component } from "preact";
import { VerifierService } from "services/verifierService";
var CONFIG = require("Config");
//import * as styles from './profile.css';
interface PassportProps { token?: string; path?: string }
interface PassportState { appId?: string; verified?: boolean }
export default class Passport extends Component<PassportProps, PassportState> {
constructor(props) {
super(props);
this.state = { appId: CONFIG.Settings.AppId };
}
async componentDidMount() {
console.log("cdm: " + this.props.token);
if (this.props.token != undefined) {
await VerifierService.post({ token: this.props.token })
.then(data => {
this.setState({ verified: data.result });
console.log(JSON.stringify(data, null, 4));
})
.catch(error => console.log(error));
}
}
render() {
return <div>Test: {this.state.verified}</div>;
}
}
I can see console.log as true inside of promise result, but i can't display it in view.
Your data in your console.log is true, so therefor data.result will give you undefined. Try to just set the data in setState.
await VerifierService.post({ token: this.props.token })
.then(data => {
this.setState({ verified: data });
console.log(JSON.stringify(data, null, 4));
})
.catch(error => console.log(error));

Categories