I've got a product card with product details shown. On the bottom, there is an 'edit' button
. When clicked
it shows a modal with prefilled input
fields, that can be edited then saved. Modal can also be closed without saving (but with input fields edited).
My problem is that when a user edits the fields, then closes modal (without saving), then opens it again, fields are not set to initial value but are shown changed.
I've tried a variable with the initial state then after closing filling the state with it, but it did not work. Tried to react refs too, no joy.
import React, { Component } from 'react'
import Modal from 'react-modal';
const customStyles = {
...
};
Modal.setAppElement('#root');
class AdminButtons extends Component {
state = {
modalIsOpen: false,
}
componentDidMount() {
const { id, inStock, name, price, type } = this.props.product
this.setState({ id, inStock, name, price, type })
}
openModal = () => {
this.setState({ modalIsOpen: true });
}
afterOpenModal = () => {
...
}
closeModal = () => {
this.setState({ modalIsOpen: false });
}
handleChange = (event) => {
const target = event.target
const input = target.value
const name = target.name
this.setState({ [name]: input })
}
render() {
const { product, remove } = this.props
const { modalIsOpen, name, inStock, price, type } = this.state
return (
<>
<button onClick={this.openModal}>EDIT</button>
<Modal
isOpen={modalIsOpen}
onAfterOpen={this.afterOpenModal}
style={customStyles}
contentLabel="Edit "
>
<h2 ref={subtitle => this.subtitle = subtitle}>Hello</h2>
<button onClick={this.closeModal}>close</button>
<div>{this.props.product.name}</div>
<form>
<label>
Name
<input name="name" type="text" value={name} onChange={this.handleChange} />
</label>
<label>inStock
<input name="inStock" type="text" value={inStock} onChange={this.handleChange} />
</label>
<label>
Price
<input name="price" type="text" value={price} onChange={this.handleChange} />
</label>
<label>
Type
<input name="type" type="text" value={type} onChange={this.handleChange} />
</label>
<button onClick={ () => {
this.props.edit(this.state)
this.closeModal() }
}>Save changes</button>
</form>
</Modal>
{product.isRemoved ?
<button> add </button> :
<button onClick={() => remove(product.id)}>remove</button>
}
</>
)
}
}
If the data from the inputs is in your component you can try something like this :
In closeModal
you can set the initial state of the component
const initialState = { name: null, inStock: null, price: null, type:null }
closeModal = () => {
this.setState({
...initialState,
modalIsOpen: false
});
}
But if the state of the inputs is coming from the Parent you need a new method to reset the data of the parent component that could be added as a callback in the same method.
const initialState = { name: null, inStock: null, price: null, type:null }
closeModal = () => {
this.setState({
modalIsOpen: false
}, () => {
this.props.resetInputData();
});
}
I'm not the sole creator of this solution but it feels relevant to this topic for anyone still getting this issue.
What I did was add a new hook variant named useTimeout which in itself is very easy to use and will reset the states for you.
import React from 'react';
export function useTimeout(callback: () => void, delay: number | null | undefined) {
const timeoutRef = React.useRef<number | undefined>();
const callbackRef = React.useRef<any>(callback);
// Remember the latest callback:
//
// Without this, if you change the callback, when setTimeout kicks in, it
// will still call your old callback.
//
// If you add `callback` to useEffect's deps, it will work fine but the
// timeout will be reset.
React.useEffect(() => {
callbackRef.current = callback;
}, [callback]);
// Set up the timeout:
React.useEffect(() => {
if (typeof delay === 'number') {
timeoutRef.current = window.setTimeout(() => callbackRef.current(), delay);
// Clear timeout if the components is unmounted or the delay changes:
return () => window.clearTimeout(timeoutRef.current);
}
return () => null;
}, [delay]);
// In case you want to manually clear the timeout from the consuming component...:
return timeoutRef;
}
Inside your modal component, import the useTimeout hook like below:
import { useTimeout } from '../../../hooks/useTimeout';
Use it above the return() of your component like below:
useTimeout(() => reset state), activate when true ? when true wait milliseconds before : null);
example:
useTimeout(() => setState({ ...state, currentStep: '' }), !props.open ? 350 : null);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With