setState() not mutating state immediately - javascript

I have a parent component that uses a get request to retrieve a JWT Token and then passes that token as a prop down to a child component. That token gets passed in another get request to authorize and retrieve data. On the method that does that get request, I am using setState after the request is successful to update the state of an empty array. The problem is that it is lagging behind due to setState not mutating the state quickly enough and the array is staying empty. I am trying to pass that array value as a prop to a child component. Any help is appreciated.
App.js - Parent Component
class App extends Component {
constructor(props) {
super(props);
this.state = {
token: '',
};
this.getToken = this.getToken.bind(this);
}
getToken() {
fetch('https://login-cmhmanagement.itg.cct-pubweb.com/nofapsaml', {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json; charset=utf-8',
},
})
.then(response => response.json())
.then(data => {
this.setState({ token: data });
});
}
componentDidMount() {
this.getToken();
}
render() {
const { token } = this.state;
return (
<div className="app-container">
<Navigation
token={token}
/>
</div>
);
}
Navigation.Js
export default class Navigation extends Component {
constructor(props) {
super(props);
this.state = {
user: [],
value: '',
};
this.getUserData = this.getUserData.bind(this);
}
componentDidMount() {
setTimeout(() => {
this.getUserData();
}, 2000);
}
getUserData() {
const { token } = this.props;
let auth = token;
fetch(url, {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${auth}`,
},
})
.then(response => response.json())
.then(result => {
this.setState({ user: result });
});
}
render() {
const { user } = this.state;
return (
<SideBarStyled>
<UserInfo
authorizedLots={user.authorizeLots}
/>
</SideBarStyled>
);
}

You should never rely on timeout, because you never know the network latency.
Rather use like below :-
export default class Navigation extends Component {
constructor(props) {
super(props);
this.state = {
user: [],
value: '',
};
this.getUserData = this.getUserData.bind(this);
}
componentDidUpdate(prevProps) {
if(prevProps.token !== this.props.token){
this.getUserData();
}
}
getUserData() {
const { token } = this.props;
let auth = token;
fetch(url, {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${auth}`,
},
})
.then(response => response.json())
.then(result => {
this.setState({ user: result });
});
}
render() {
const { user } = this.state;
return (
<SideBarStyled>
<UserInfo
authorizedLots={user.authorizeLots}
/>
</SideBarStyled>
);
}

Related

React search option from API needs running twice?

When connecting to the Spotify API through a React app I enter a term to the search box and it loads fine but refreshes the page immediately. Upon searching a second time it works perfectly fine? Is this an obvious error I am missing?
I have included the code below and appreciate any help
Spotify Fetch
const clientId = '//my api key//';
const redirectUri = 'http://localhost:3000/';
let accessToken;
getAccessToken() {
if(accessToken) {
return accessToken;
}
const hasAccessToken = window.location.href.match(/access_token=([^&]*)/);
const hasExpiresIn = window.location.href.match(/expires_in=([^&]*)/);
if (hasAccessToken && hasExpiresIn) {
accessToken = hasAccessToken[1];
const expiresIn = Number(hasExpiresIn[1]);
window.setTimeout(() => accessToken = '', expiresIn * 1000);
window.history.pushState('Access Token', null, '/');
return accessToken;
} else {
const accessUrl = `https://accounts.spotify.com/authorize?client_id=${clientId}&response_type=token&scope=playlist-modify-public&redirect_uri=${redirectUri}`;
window.location = accessUrl;
}
},
Spotify Search
search(term) {
const accessToken = Spotify.getAccessToken();
return fetch(`https://api.spotify.com/v1/search?type=track&q=${term}`, {
headers: {
Authorization: `Bearer ${accessToken}`
}
}).then(
response => {
if (response.ok) {
return response.json();
} else {
console.log('API request failed');
}
}).then(
jsonResponse => {
if(!jsonResponse.tracks) {
return [];
}
return jsonResponse.tracks.items.map(track => ({
id: track.id,
name: track.name,
artist: track.artists[0].name,
album: track.album.name,
uri: track.uri,
preview: track.preview_url,
art: track.album.images[2].url
}));
});
},
Search Component
import React from 'react'
import './searchbar.css';
class Searchbar extends React.Component {
constructor(props) {
super(props)
this.state = { term: ''}
this.search = this.search.bind(this)
this.handleTermChange = this.handleTermChange.bind(this)
}
search() {
this.props.onSearch(this.state.term)
}
handleTermChange(e) {
this.setState( {term: e.target.value} )
}
render() {
return <div className="SearchBar">
<input placeholder="Enter A Song, Album, or Artist" onChange = {this.handleTermChange} />
<button className="SearchButton" onClick = {this.search}>SEARCH</button>
</div>
}
}
export default Searchbar;

400 BAD REQUEST when POST using Axios in React

Can any help me with this?
I keep getting a 400 bad request from Axios.
I can pass a GET request and confirm its working fine.
I create http-common.js file with following code:
import axios from 'axios';
export default axios.create({
baseURL: 'https://5fa97367c9b4e90016e6a7ec.mockapi.io/api',
headers: {
'Content-type': 'application/json'
}
});
Then,I create a service that uses axios object above to send HTTP requests.
TodoService.js
import http from '../http-common/http-common';
const getAll=()=>{
return http.get('/todos');
};
const get=id=>{
return http.get(`/todos/${id}`);
};
const create=data=> {
return http.post('/todos',data);
};
const update=(id,data)=>{
return http.put(`/todos/${id}`,data);
};
const remove = id => {
return http.delete(`/todos/${id}`);
};
const removeAll = () => {
return http.delete(`/todos`);
};
const findByTitle = title => {
return http.get(`/todos?title=${title}`);
};
export default {getAll,get,create,update,remove,removeAll,findByTitle};
Then, I use TodoDataService.create(data) ... in AddTodos component.
AddTodos.js
import React, { useState } from 'react';
import TodoDataService from '../services/TodoService';
const AddTodos = () => {
const initialTodoState={
id:null,
title: '',
isDone: false,
user: ''
};
const [todo,setTodo]=useState(initialTodoState);
const [submitted,setSubmitted]=useState(false);
const handleInputChange=event=>{
const {name,value}=event.target;
setTodo({...todo,[name]:value});
};
const saveTodo =()=>{
var data={
title: todo.title,
isDone:todo.isDone,
user: todo.user
};
console.log(data);
TodoDataService.create(data)
.then(response => {
setTodo({
id:response.data.id,
title: response.data.title,
isDone: response.data.isDone,
user: response.data.user
});
setSubmitted(true);
console.log(response.data);
})
.catch(e => {
console.log(e);
});
};
const newTodo=()=>{
setTodo(initialTodoState);
setSubmitted(false);
};
return (
<div className="submit-form">
{submitted ? (
<div> //...
) : (
<div>
<div className="form-group"> //... </div>
<div className="form-group"> //... </div>
<button onClick={saveTodo} className="btn btn-success">
Submit
</button>
</div>
)}
</div>
)
}
export default AddTodos;
When clicked Submit it's giving this error:
I recreate your api call and got this response:
await fetch('https://5fa97367c9b4e90016e6a7ec.mockapi.io/api/todos', {
method: 'POST', body: JSON.stringify({id: "123",title: "homework", isDone: false, user: "foo"})})
.then(response => response.json())
.then(data => {
console.log(data)
})
error 400 "Max number of elements reached for this resource!"
you need to delete some records in order to insert new ones
so after deleting a record:
await fetch('https://5fa97367c9b4e90016e6a7ec.mockapi.io/api/todos/1', {
method: 'DELETE'})
.then(response => response.json())
.then(data => {
console.log(data)
})
VM623:5 {id: "1", title: "deneme", isDone: true, user: "cafererensimsek"}
and posting a new one, now it works

how post props redux React

I would like to explain my problem of the day.
I can't post "this.props.total",
I do not understand how to post a props, can you help me pls?
currently the props works correctly.
import React, { Component } from 'react';
import { CardText, } from 'reactstrap';
import { connect } from 'react-redux'
class thisPropsFortotal extends Component {
handleSubmit = (e) => {
e.preventDefault();
const config = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({this.props.total}),
};
const url = entrypoint + "/alluserpls";
fetch(url, config)
.then(res => res.json())
.then(res => {
if (res.error) {
alert(res.error);
} else {
alert(`ajouté avec l'ID ${res}!`);
}
}).catch(e => {
console.error(e);
}).finally(() => this.setState({ redirect: true }));
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<button type="submit">Add</button>
</form>
<CardText>{this.props.total} € </CardText>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
total: state.addedItems.reduce((acc, item) => { return acc + (item.quantity *
item.price) }, 0)
//addedItems: state.addedItems
}
}
export default connect(mapStateToProps)(thisPropsFortotal)
Do you have an idea of how to fix this? Neff
You are attempting to stringify {this.props.total}, which is invalid syntax.
You can pass an object explicitely defining the total property like so:
body: JSON.stringify({total: this.props.total}),
Or, simply stringify the this.props object itself:
body: JSON.stringify(this.props),

How to access mutation data from component?

This is how I extend my component:
const ComponentWithMutation = graphql(GQL_MUTATION_ACTIVATE,
{
options: (props) => ({
variables: {
foo: props.foo,
bar: props.bar,
},
}),
})(ActivateEmail);
Now inside component:
class ActivateEmail extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
const { match, mutate } = this.props;
mutate({
variables: { token: match.params.atoken },
});
}
render() {
return (
<div>
// I need to access data, error, loading here...
</div>
);
}
}
I would like to access data, error, loading. How can I do it in render method?
regarding apollo-client docs, mutation returns a promise that returns mutation information like data, error, loading, etc..
so the codes should look like:
constructor() {
this.state = {
dataLoading: true,
dataLoadError: false,
}
}
async componentDidMount() {
try {
const { match, mutate } = this.props;
const { data: { yourMutationData }, error} = await mutate({
variables: { token: match.params.atoken },
});
this.setState({
dataLoading: false,
data: yourMutationData
});
}
catch (err) {
this.setState({
dataLoading: false,
dataLoadError: true,
});
}
}
or you can use a normal promise like that:
componentDidMount() {
const { match, mutate } = this.props;
mutate({
variables: { token: match.params.atoken },
})
.then( (query) => {
console.log(query); //here you should get the same result with the code above.
this.setState({
dataLoading: false,
data: query.data.yourMutationData
});
})
.catch(err => {
this.setState({
dataLoading: false,
dataLoadError: true,
});
})
}

How to use the response in fetch request React Native

I am new in react native world and (JS).
I want to send phone number and password to the server to login. I can send data and receive response, however, I don't how I should handle response. I have a function called _response_recognizer. But it is not working. Even setStat. All of the tutorials only say how to connect to server and how fetch data from it. What is the best approach to use response in my login form. If it's status is 200 I want to navigate another screen, else I want to toast a message.
import React, {Component} from 'react';
import {
Platform,
StyleSheet,
Text,
View,
TextInput, Button
} from 'react-native';
export default class LoginForm extends Component<{}> {
constructor(props) {
super(props);
this._onLogInPressed = this._onLogInPressed.bind(this);
this._response_recognizer = this._response_recognizer.bind(this);
this.state = {
phone_number: '',
password: '',
data: {}
};
}
_response_recognizer(data: string ){
}
_onLogInPressed = () => {
var data = {
'phone_number': this.state.phone_number,
'password': this.state.password
}
fetch("http://192.168.1.12:5000/login", {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(data)
}).then(function(response){
return response.json();
}).then(function(data){
console.log(data)
this._response_recognizer(data)
}) .catch((error) => {
console.log("Error" + error);
});
};
render() {
return (
<View style={styles.flow}>
<Text style={styles.text}>phone number:</Text>
<TextInput keyboardType='numeric'
style={styles.input}
ref="phone_number"
onChangeText={(phone_number) => this.setState({phone_number})}
maxLengt={11}
value={this.state.phone_number}
/>
<Text style={styles.text}>password:</Text>
<TextInput style={styles.input} secureTextEntry={true} ref="password"
onChangeText={(password) => this.setState({password})}
value={this.state.password}/>
<Button style={styles.button} onPress={this._onLogInPressed} title='login'/>
</View>
);
}
}
Two things.
Your _response_recognizer function is requesting data: string but you are returning an json object:
.then(function(response){
return response.json();
}).then(function(data){
console.log(data)
this._response_recognizer(data)
})
Change that to data: object.
Secondly, you are using function declarations (function(){}) in your .then's. Without directly binding this, you lose the scope your Class functions. Change them to an arrow function (() => {}) to fix the scope issue:
.then((response) => response.json())
.then((data) => {
console.log(data)
this._response_recognizer(data)
})
You can also opt to remove one of the .then operations:
.then((response) => {
console.log(response.json())
this._response_recognizer(response.json())
})
✌🏾
check this ...
i hope this code helps you
export default class LoginForm extends Component<{}> {
state = {
data:[],
}
_onLogInPressed = () => {
fetch('http://192.168.1.12:5000/login',{
method:'POST',
headers:{
'Accept':'application/json',
'Content-Type':'application/json',
},
body:JSON.stringify({
'phone_number': this.state.phone_number,
'password': this.state.password
})
})
.then((response) => response.json())
.then((res) =>{
if(res.success === true){
alert(res.response);
let datadata = res.data;
this.setState({data:datadata})
} else {
alert(res.response);
}
})
.done();
};
//// Render function
////Rander function
}

Categories

Resources