Access this from another class React Native - javascript

I am currently factoring my code so as not to repeat the same lines x times, so I created a Functions.js file which I use to call functions from other classes. The problem is, that I cannot execute the function while keeping the properties of this to carry out setState, redirects etc. Here is an example, it will be more telling:
Class in functions.js :
export class KoHttpRequest extends React.Component {
constructor(props) {
super(props);
this.postRequest = this.postRequest.bind(this);
}
postRequest = async(url, json, accessToken) => {
this.setState({loaded: false, validatingAction: false});
fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization' : 'Bearer '.concat(accessToken)
},
body: json
}).then((response) => {
if (response.ok === true) {
this.fetchData().then(() => {
this.setState({loaded: true}, () => {
this.userIsValidatingAnAction();
setTimeout(() => {this.setState({validatingAction: false})}, 1000);
});
})
} else {
let error = JSON.stringify(response.headers.map);
this.props.navigation.navigate('Accueil', {failedAction: true, errorReason: error.split('"error-reason":').pop().split('}},')[0].concat(' URL : '.concat(response.url))});
}
})
.catch((error) =>{
console.error(error);
});
}
render() {
return null;
}
}
And in the file where I want to call it :
import { KoHttpRequest } from '../Components&Functions/Koust.js';
createNewInvoice = () => {
new KoHttpRequest().postRequest('https://koupp.com/apex/rest/mobile/facture', JSON.stringify({
type:'C',
numero:this.state.invoiceNumber,
date_liv:this.state.pickedDate,
provider_id:this.state.selectedProvider
}), this.state.accessToken);
};
So, to explain clearly, in the class, the .then() and .error() are same for all request I do in my app, that's why I need the code here and not in the class that is calling it.
Unfortunely, I don't understand how I can tell the function that the 'this' referenced to use is in the other component. Cause actually the function is using themselve props..
Thanks for help.

I'm just trying to access the setState of class that is calling it.
In Functions.js, when it's using setState, I want it set the state of the other class actually
EDIT :
I think I found a solution using a callback.
createNewInvoice = () => {
this.setState({loaded: false, validatingAction: false}, () => {
new KoHttpRequest().koPostRequest('https://koupp.com/apex/rest/mobile/facture', JSON.stringify({
type:'C',
numero:this.state.invoiceNumber,
date_liv:this.state.pickedDate,
provider_id:this.state.selectedProvider
}), this.state.accessToken, this.props, function(result) {
if (result.status === 200) {
this.fetchData().then(() => {
this.setState({loaded: true}, () => {
this.userIsValidatingAnAction();
setTimeout(() => {this.setState({validatingAction: false})}, 1000);
});
})
}
});
});
};
But now, that's the callback function that can't access "this".
EDIT_2:
Find it. Just need to replace function() {..} by () => {..}
Thanks!

Related

I don't know how to get data from fetch correctly

I have a Users class where I want to get data from the server for later writing it to state and passing data from state to the child component
export default class Users extends Component {
constructor(props) {
super(props);
this.state = {
users: this.getUsers(),
};
}
getUsers = async () => {
await return fetch(`http://localhost:3001/users`, {
method: 'POST',
accept: 'application/json'
}).then(res => {
if(res.ok) {
res.json();
}
})
}
}
this is what the console shows me when I output data about this.state.users
I tried to look for similar situations, but I didn't find anything worthwhile, so I ask for help here. I would be grateful for any advice or help. I'm only learning asynchrony in js
if you use async await, you don't have to pass callback function, just await the promises and update the state incase of successful response.
getUsers = async () => {
try {
const response = await fetch(`http://localhost:3001/users`, {
method: 'POST',
accept: 'application/json'
});
const users = await response.json();
this.setState({ users });
} catch (error) {
console.log(error);
}
}
and instead of calling getUsers function from the constructor, use componentDidMount
componentDidMount() {
this.getUsers();
}
and your state should be initially null or an empty array
this.state = {
users: []
};
Add componentDidMount and call getUsers and set state.
this.state = {
users: [],
};
getUsers = async () => {
return await fetch(`http://localhost:3001/users`, {
method: 'POST',
accept: 'application/json'
}).then(response => response.json())
.then(res => { this.seState({ users: res })})
.catch(e => { console.log(e)})
}
componentDidMount = () => {
this.getUsers()
.catch(e => console.log(e)
}

How can I run a code after another has already ended running?

In less than 1 second, I have to post something into a JSON file and then get that exact data updated. When running the code, it seems that I post the data in the JSON file but when I try to get it, it gets the old data, not the updated one.
How can i run get method after post method has ended running?
I ran this post method
import Game from "./components/Game/Game";
class App extends React.Component {
postUserInfo(){
fetch("http://localhost:8080/api/users" , {
method: "post" ,
mode: "cors",
headers: {
"Content-type": "application/json",
},
body:JSON.stringify({username:this.state.userInput, bestscore:0})
})
.then((res) => res.json())
.then((data => {console.log(data)}))
.catch((error) => {
console.log(error);
});
}
}
and then in the other class I run this get method right after the post method
class Game extends React.Component {
getUserInfo() {
fetch("http://localhost:8080/api/users" , {mode: "cors"})
.then((res) => res.json())
.then((data => {
this.setState({ usersInfoArray: data})
var _userid = data[data.length-1].id;
var _username = data[data.length-1].username;
var _bestscore = data[data.length-1].bestscore;
this.setState({ userid: _userid, username: _username, bestscore: _bestscore});
}))
}
}
componentDidMount(){
this.getUserInfo();
this.render();
}
I guess you may call postUserInfo() in another component then move to new Component
then after component mount, call getUserInfo()
Am i right?
If so
your navigate to(or create) other component logic must in postUserInfo()
near
.then((data => {console.log(data)}))
Probably the easiest way to do this is to maintain a dataPosted flag in App's state and pass that flag to the Game component. If the dataPosted flag is true, then load the data.
App.jsx
import Game from "./components/Game/Game";
class App extends React.Component {
constructor() {
super();
this.state = { dataPosted: false }
}
postUserInfo(){
fetch("http://localhost:8080/api/users" , {
method: "post" ,
mode: "cors",
headers: {
"Content-type": "application/json",
},
body:JSON.stringify({username:this.state.userInput, bestscore:0})
})
.then((res) => res.json())
.then(data => {
this.setState({ dataPosted: true })
})
.catch((error) => {
console.log(error);
});
}
}
render() {
<Game dataPosted={this.state.dataPosted} />
}
}
Game.jsx
class Game extends React.Component {
componentDidUpdate() {
if (this.props.dataPosted) {
this.getUserInfo();
}
}
getUserInfo() {
fetch("http://localhost:8080/api/users" , {mode: "cors"})
.then((res) => res.json())
.then((data => {
this.setState({ usersInfoArray: data})
var _userid = data[data.length-1].id;
var _username = data[data.length-1].username;
var _bestscore = data[data.length-1].bestscore;
this.setState({ userid: _userid, username: _username, bestscore: _bestscore});
}))
}
}

ReactJs : How to prevent componentWillUpdate from re-rendering multiple times

I am creating a simple Todo App, I am using componentDidMount to display the data from the database. But the problem is, Once I add a new data the data gets stored but it doesn't display on to the page unless I refresh it.
Then I came across componentDidUpdate. It works perfectly, But it re-renders multiple times, What I mean is it keeps requesting the server to check for new data.
I am using Express for backend
So could anyone tell me how to prevent this ? or if there is any better solution?
Here is the current code:
class Navbar extends Component {
state = {
userArray: [],
username: "",
email: ""
};
//Storing the Data
addBtn = e => {
e.preventDefault();
var data = {
username: this.state.username,
email: this.state.email
};
fetch("/user", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data)
})
.then(response => {
if (response.status >= 400) {
throw new Error("Bad response from server");
}
return response.json();
})
.then(data => {
console.log(data);
if (data === "success") {
console.log("Yay");
}
})
.catch(err => {
console.log(err);
});
console.log(this.state.userArray);
};
componentDidMount() {
this.displayData();
}
componentWillUpdate() {
this.displayData();
}
//Displaying the Data
displayData() {
fetch("/user")
.then(data => data.json())
.then(data => {
this.setState({
userArray: data
});
});
}
//Handling the input values
logChange = e => {
this.setState({
[e.target.name]: e.target.value
});
};
So, let's try and understand why there was a lot of calls to the server.
When componentDidMount is created, you called displayData, which then setState. As soon as setstate is called, it calls componentDidUpdate which calls displayData again, which then calls setState. And the loop goes on (probably till you run out of memory).
You could try this class:
import React from 'react';
export default class Navbar extends React.Component {
state = {
userArray: [],
username: '',
email: ''
};
componentDidMount() {
this.displayData();
}
addBtn = e => {
e.preventDefault();
var data = {
username: this.state.username,
email: this.state.email
};
fetch('/user', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
})
.then(response => {
if (response.status >= 400) {
throw new Error('Bad response from server');
}
return response.json();
})
.then(data => {
console.log(data);
if (data === 'success') {
this.displayData();
}
})
.catch(err => {
console.log(err);
});
};
displayData() {
fetch('/user')
.then(data => data.json())
.then(data => {
this.setState({
userArray: data
});
});
}
}
Basically, what I did was I removed the call to displayData in componentDidUpdate and then called the displayData when the ApI call was successful
componentDidMount is the right place to load the first time, and then, after creating new Todo, you need to refresh the list right after POST request complete
.then(data => {
console.log(data);
if (data === "success") {
console.log("Yay");
this.displayData();
}
})
To impove performace, you should return new Todo record after POST, so you only push it to the list userArray in state, no need to fetch whole list again
For this, you need to first understand how componentDidMount and componentWillUpdate works in React.
They are lifecycle methods of react.
componentDidMount gets called after the component is mounted. It gets called only once and never gets called again if not unmounted and mounted again.
componentWillUpdate gets called every time state changes and re-rendering is going to happen.
As commented by #trixn:
You need to call this.setState() in addBtn when you have the data instead of repeatedly calling this.displayData()
Everyone gave the right answer , But there is a tiny mistake.
You should call the displayData() outside of the if condition
.then(data => {
console.log(data);
if (data === "success") {
console.log("Yay");
}
this.displayData();
})

React-native Invoke API from one common handler class

I have a common function which uses FETCH to get data from external web service. this function will be invoked and parsed in multiple screens under componentDidMount(). instead of repeating the same code at multiple places, I put below under a common class, but unfortunately, data is not returned to those screens.
Common Function
export function convertValue(fromVal, toVal) {
var requestObj = {};
let apiEndpoint = '<target endpoint>'
return fetch(apiEndpoint, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
})
.then((response) => response.json())
.then((responseJson) => {
return responseJson;
})
.catch((error) => {
console.log('Error: ', error);
});}
Sample call below, and no pop-up when screen loaded.
componentDidMount () {
AsyncStorage.getItem('user_default').then((value) => {
this.setState({userDefault: value});
}).then((value) => {
var sample = convertValue('A', 'B');
Alert.alert(
'Success',
JSON.stringify(sample),
[
{text: 'OK',
onPress: () => {
console.log('.');
}}
]
)
});}
componentDidMount () {
AsyncStorage.getItem('user_default').then((value) => {
this.setState({userDefault: value});
convertValue('A', 'B').then((json)=>{
alert(json)
})
})}
This might work for you. The problem was improper chaining of asynchronous calls.
Nick is right, found the right way -
convertValue('A', 'B')
.then((responseJson) => {
this.setState({returnedValue: responseJson.convertedValue});
});

Sending results from fetch to another part of program

I am creating an app in React Native and have bumped in to some major issues with fetching data from my server and using it in my program.
My architechture differs a bit from the example provided by React Native in their documentation, but I have tried a bunch of different ways. The token is correct and I am obviously calling the method in a sense correctly, but it does not return the data to the other side of my program.
In Methods.js
exports.loginUser = function(TOKEN) {
fetch(baseUrl + 'login' , {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
accessToken: TOKEN,
},)
})
.then((response) => response.text())
.then((responseText) => {
console.log(typeof responseText);
return responseText
})
.catch((error) => {
console.warn(error);
});
};
Where it logs the type of the data as a string, and it prints out correctly when I call it as is. However, my app can't retrieve the data in any kind of manner, it just returns as undefined.
In Home.js
var Method = require('../Services/Methods');
.
.
.
var ComponentTwo = React.createClass({
getInitialState: function() {
return {
text: 'Loading...',
}
},
componentDidMount: function() {
{
this.setState({
text: Method.loginUser(AccessToken)
})
}
},
render: function() {
console.log(Method.loginUser(AccessToken));
console.log(this.state.text);
I am in trial and error mode right now, but both of the logs returns undefined, except for my log in Methods.js, so I think there is an issue with just hitting return responseText, but I don't know any other way since they are in two separate files. So I think the issue is within Method.JS since calling it fails in every way I've tried.
I think you have to return a promise from your loginUser function, something like:
exports.loginUser = function(TOKEN) {
return new Promise((resolve, reject) => {
fetch(baseUrl + 'login' , {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
accessToken: TOKEN,
},)
})
.then((response) => response.text())
.then((responseText) => {
console.log(typeof responseText);
resolve(responseText);
})
.catch((error) => {
reject(error);
});
});
};
And then call your function like this:
Method.loginUser(AccessToken)
.then((res) => console.log(res))
.catch((error) => console.log(error))
.done();
I have not verified that the above code is working, it's just to give you an idea.

Categories

Resources