ReactJS state reset itself - javascript

I am having a strange (to me) issue with my ReactJS code.
I just started learning ReactJS so I might be doing something very stupid, but this is what's happening.
Link to codepen: https://codepen.io/Scyleung/pen/XyVovg
I am have this component like so
class LeaseData extends React.Component {
constructor(props) {
super(props);
this.state = {
id: null,
ready: false,
data: null,
error: null,
};
this.update = this.update.bind(this);
//this.getNewJson(1);
}
update(newID) {
this.setState({
id: newID,
ready: false,
data: null,
error:null,
});
console.log("From Main: " + newID + " " + this.state.id);
this.getNewJson(newID);
}
getNewJson(id) {
let url = "https://hiring-task-api.herokuapp.com/v1/leases/"+id;
fetch(url)
.then(res => res.json())
.then(
(result) => {
console.log(result);
this.setState({
ready: true,
data: result
});
},
(error) => {
console.log("Error: " + error.message);
this.setState({
ready: true,
error: error
});
}
)
}
render() {
if (this.state.error) {
console.log("ERROR")
return (
<div>
<Form callback = {this.update}/>
Error: {this.state.error.message}
</div>);
} else if (!this.state.ready) {
console.log("Waiting")
return (<Form callback = {this.update}/>);
} else {
console.log("Displaying")
return (
<div>
<Form callback = {this.update}/>
{this.state.data.rent}</div>
);
}
}
}
I have a Form that calls update() when the user submit the form.
First issue, inside update() the console.log() always say this.state.id is null, even after submitting the form multiple times.
Second issue, update() should call getNewJson() that should set this.state.error, if an error happens in fetch. As much in render() it should console.log("ERROR"), which it does, so that's good. However immediately afterward it would go to console.log("Waiting") again. So maybe related to the first issue, since the state got reset.
Third issue, why am I getting an error on the fetch like 80% of the time?
The strangest thing is, if I uncomment the this.getNewJson(1) in the constructor, all the problems disappears!!

The main issue I assume is that onSubmit does what you want but then reloads the page cancelling the request. What you need to do to prevent this is to call e.preventDefault() after calling the callback function.
Changing your onSubmit to something like this should fix the main issue
onSubmit = {(e) => {
this.props.callback(this.state.value);
e.preventDefault();
}}
https://codepen.io/anon/pen/QJaeyY
Secondly, to get the error from fetch, you should use .catch() instead of the second callback function in then() as this is the proposed syntax and should work with most browsers.

Related

how to make display message in page after click confirm alert in react js

in my below code using react js i want to make when i click on confirmation alert ok then its show display message success in web page.in my below i when i click on button its confirmation alert is show and when i click on ok then message is not display in web page.
How can we do that is there any help. Its very thankful.
Anyone plz help me out this.
Please check here in my code what i am try to achive
check
The code sandbox you shared was 'logging' the message rather than displaying on the screen. I have updated the code to update the state according to the option user selected.
handleAgree = () => {
this.setState({ agreedState: "I agree!" });
this.handleClose();
};
handleDisagree = () => {
this.setState({ agreedState: "I do not agree!" });
this.handleClose();
};
And finally we can display the message:
{/* Showing message according to the selected option */}
<h1>{this.state.agreedState}</h1>
Here is the updated code sandbox.
I don't really get what you want to do.
You got the code working to display the question prompt.
If you would like to get rid of that only record, you could simply add a ref to your class Component, like this:
constructor(props) {
super(props);
this.myRef = React.createRef(null);
}
Then add the function to handle your deletion logic, e.g: make a POST request to delete that specific item.
handleRemoveItem = (e) => {
const res = window.confirm("Delete the item?");
/**
* Probably a POST request to delete
* the record with the key 'e'.
* Or handle múltiples refs.
*/
if (res)
this.myRef.current.remove();
}
Add ref to button, and you've already done the rest:
<button
className="btn btn-danger"
ref={this.myRef}
onClick={this.handleRemoveItem}
>
If you'd like to display an error or success message, add props to your component, so it's reusable across multiple use cases. But, in order to let you visualize this behaviour, this could be useful:
{(this.state.error || this.state.success) && (
<span className="message">
{this.state.error
? this.state.errorMessage
: this.state.successMessage}
</span>
)}
Add the state to the constructor:
this.state = {
error: false,
success: false,
errorMessage: 'Your error message!',
successMessage: 'Your success messsage'
};
Finally, the logic to your handler:
handleRemoveItem = (e) => {
const res = window.confirm("Delete the item?");
/**
* Probably a POST request to delete
* the record with the key 'e'.
* Or handle múltiples refs.
*/
if (res) {
this.myRef.current.remove();
this.setState({ success: true });
setTimeout(() => this.setState({ success: false }), 3000);
} else {
this.setState({ error: true });
setTimeout(() => this.setState({ error: false }), 3000);
}
}
Code
You can use const res = window.confirm("Delete the item?"); to check click OK or Cancel from alert. After that, you can show your message success as you want when the user clicks OK.
https://codesandbox.io/s/eager-haslett-y63ld?file=/src/index.js

Error using SetTimeOut with React/redux dispatch function

So I have this state for handling error messages and that state have two actions
The first one for setting the message:
export const setNotification = (message) => {
return {
type: "SET_NOTIFICATION",
data: {
message,
visibility: "visible"
}
}
}
And the second for removing the message after 5 seconds:
export const clearNotification = (seconds=5) => {
setTimeout(()=> { return {
type: "REMOVE_NOTIFICATION",
data: {
message: "",
visibility: "hidden"
}
}}, seconds * 1000)
}
And when calling the second function called ClearNotification I get this error:
Error: Actions must be plain objects. Use custom middleware for async actions.
Why am I getting this message and how can I fix it?
Thanks.
That's because you can not return a function as action. The actions are simple objects of the shape ´{type: string, ...any}´. If you want to return a function you should google for redux-thunk or something like redux-saga or redux-observable but those are quite tricky.
This link has an example of what you want to do. https://github.com/reduxjs/redux-thunk#motivation

react-redux's dispatch fails to call appropriately in the form handling function

I'm building cryptocurrency exchange app with third party api. My problem arises from the calling store.dispatch() from the ConvertForm component. Although, i will still use connect(), but i want to test the form handing life-cycle first. Anytime i click submit button with handleCryptoSubmit() event handle, the store.dispatch() supposed to call the fetchCryptoToCurrencyBegin() (only using this for texting), the functon supposed to change the reduce's state's loading property to TRUE. On submiting the form, after verification of the inputs, the fetchCryptoToCurrencyBegin() do not alter the loading property to True until I change the either of the value of cryptoCode form field or currencyCode form field again. And it will automatically call the fetchCryptoToCurrencyBegin() without click submit after the change.
I have check my onChangeHandle() if i make any mistake in the form handling function and the reduce and action codes. Everything seems to be working fine. Although i'm new to react, i have search internet for possible answers without any success. I have used setState() to fetch api data, it works on first try. I don't think connecting the component to redux through mapdispatch will work either. My problem is react-redux
///this is my inner state for form validation
this.state={
cryptoToCurrencyState:{
quantityAmount: {
figureAmount: null,
amountErrorMessage: '',
validInput: true,
validForSubmit: false
},
cryptoCode: {
tokenCode: '',
},
currencyCode: {
nationalCode: '',
}
},
}
/// this is my form field change handler.
// for reusing the targetProperty logic
targetPropertyUtility = (target) => {
let objectTarget;
if (target.name === 'quantityAmount'){
return objectTarget = 'figureAmount';
}else if (target.name === 'cryptoCode'){
return objectTarget = 'tokenCode';
}
return objectTarget = 'nationalCode';
};
handleCryptoChange = (e) => {
const regexp = new RegExp(`^-?[0-9]*$`);
const target = e.target;
e.persist();
// check above arror function to understand targetPropertyUtility
let targetProperty = this.targetPropertyUtility(target)
if (target.name === 'quantityAmount' && !regexp.test(target.value)){
this.setState({
...this.state,
cryptoToCurrencyState:{
...this.state.cryptoToCurrencyState,
[target.name]: {
...this.state.cryptoToCurrencyState[target.name],
[targetProperty] : target.value,
amountErrorMessage: 'input only valid number',
validInput: false,
validForSubmit: false
}
}
});
}else if(target.name === 'quantityAmount' && regexp.test(target.value)){
this.setState({
...this.state,
cryptoToCurrencyState:{
...this.state.cryptoToCurrencyState,
[target.name]: {
...this.state.cryptoToCurrencyState[target.name],
[targetProperty] : target.value,
amountErrorMessage: null,
validInput: true,
validForSubmit: true
}
}
});
}else{
this.setState({
...this.state,
cryptoToCurrencyState:{
...this.state.cryptoToCurrencyState,
[target.name]: {
...this.state.cryptoToCurrencyState[target.name],
[targetProperty] : target.value,
}
},
});
}
};
///this is my onSubmit hander
// this event handle the submit of cryptocurrency to national currency
handleCryptoSubmit = (e) => {
e.preventDefault();
const {cryptoToCurrencyState} = this.state;
const {quantityAmount}= cryptoToCurrencyState;
lauch action thunk if the form is valid
/// if form is not valid, validation error will be displayed and the action thunk will be prevented
/// There will be main error display to show the form is not valid
if(quantityAmount.validForSubmit){
/// action for testing
store.dispatch(fetchCryptoToCurrencyBegin());
}else if(!quantityAmount.figureAmount){
this.setState({
...this.state,
cryptoToCurrencyState:{
...this.state.cryptoToCurrencyState,
quantityAmount: {
...this.state.cryptoToCurrencyState.quantityAmount,
amountErrorMessage: 'The field is required',
validInput: false,
validForSubmit: false
},
}
});
}
I want the store.dispatch() to trigger fetchCryptoToCurrencyBegin() on the verification on the form field. Thanks.
I was able to solve the problem by using connect on the component. Thus, store.dispatch() will not effectively work in a component if the component is not connected to the HOC connect/Provider of the react-redux.

React Native - run functions synchronously

I have written the following code, it runs smoothly but I have encountered a question:
submitFormToBackend = async () => {
if (this.paymentMethod === 'apple-pay') {
this.setState({ showLoadingIndicator: true }); // <-- below await setTimeout can confirm this line run before it
}
let requester = new ApplePayRequester({...this.form});
let applePay = new ApplePay();
await setTimeout(async () => {
let cardTokenResponse = await applePay.getCardToken();
if (cardTokenResponse.isSuccess()) {
requester.setCardToken(cardTokenResponse.message);
let response = await requester.pushToBackend();
this.setState({ showLoadingIndicator: false }); //<-- below setTimeout can confirm this line run before them
if (response.isSuccess()) {
setTimeout(() => { this.navigator.backToPreviousScreen(); }, 800);
} else {
setTimeout(() => { Alert.alert('your purchase has error. Try again'); }, 800);
}
} else {
this.setState({ showLoadingIndicator: false });
setTimeout(() => { Alert.alert('cannot get your card token.'); }, 800);
}
}, 800);
};
My render() in that component:
render() {
return (
<View style={styles.form}>
<LoadingIndicator visible={this.state.showLoadingShader} />
<InputBox />
<InputBox />
<SubmitButton />
</View>
);
}
As you see there are a lot of setTimeout() functions, it seems like functions will crash together if I don't use setTimeout() to restrict the functions run one by one.
However, it's not a good practice as there is no default millisecond for success running (the millisecond can set to 700ms or 1500ms or etc.). Therefore I would like to ask is there any solution to confirm previous function has run before next function start, other than using setTimeout()?
UPDATE
Procedures:
Step 1 - Press submit button
Step 2 - Pop up a confirmation modal
Step 3 - User confirm, dismiss confirmation modal, set showLoadingIndicator to true to show loading indicator
Step 4 - Call ApplePay and pop up ApplePay UI
Step 5 - User confirm, set showLoadingIndicator to false to dismiss loading indicator and navigate previous screen
Problems encountered when not using setTimeout():
Step 4 - ApplePay UI cannot pop up after setting showLoadingIndicator to true, below is the code that encountered problem:
let cardTokenResponse = await applePay.getCardToken();
Step 5 - Alert will be pop up before setting showLoadingIndicator to false, which stops the setting, below is the code that encountered problem:
this.setState({ showLoadingIndicator: false });
if (response.isSuccess()) {
} else {
setTimeout(() => { Alert.alert('your purchase has error. Try again'); }, 800);
}
A second optional parameter of setState function is a callback function that runs synchronously with the state change.
So you can just rely on the following:
this.setState({
//change state variables here
}, () => {
//do the next work here...
});
The callback function always run post the state is changed.
In your code, this would work:
this.setState({ showLoadingIndicator: false }, () => {
if (response.isSuccess()) {
this.navigator.backToPreviousScreen();
} else {
Alert.alert('your purchase has error. Try again');
}
});

React .setState returns type error

I'm using React v 16.3.2 and am building an app to communicate orders with a DB on Firebase, also using axios 0.18.0.
I'm expecting that once I hit a certain button (continue) it will create this spinner effect on the screen as it loads, so I have the following code:
purchaseContinueHandler = () => {
this.setState = ({loading: true});
const order = {
ingredients: this.state.ingredients,
price: this.state.totalPrice,
customer: {
name: 'Name',
address: {
street: 'teststreet 1',
zipCode: '86753',
country: 'U.S.'
},
email: 'example#example.com'
},
deliveryMethod: 'fastest'
}
axios.post('/orders.json', order)
.then(response => { this.setState( { loading: false } );
})
.catch(error => {
this.setState( { loading: false } ); //**<--This is where i get the error**
});
}
I run it and hit Continue on the app and get the error:
Unhandled Rejection (TypeError): _this.setState is not a function
and it points to the line listed above.
Ran into this documentation and tried to implement the solution that worked for him (create a constructor() and bind this to this) but that didn't work.
I was reading that this was no longer automatically added to the function but not sure what to do with that information, I'm pretty new to React still.
Any advice?
You are assigning an object to setState in the first line of code, so when you try to call it later it no longer is a function...
this.setState = ({loading: true});
should be
this.setState({loading: true})
The setState is a function, you change it to an JavaScript Object, I guess it's a tiny mistake, you have to write:
this.setState({loading: true})
Use it not change it to other things.

Categories