I have a custom form with at least two different types of Components: One for a textfield, and another for a number, and when I click the "Submit" button (itself just a button, not wrapped in a form) I want to set the state of the fields back to 0/Empty. I'm not really clear here on how to restore these to their defaults. I know that I need to pass setState()
at some point since I can't "zero out" like with traditional Javascript, but I am confused since the click operation would never reference the components. What am I missing here?
import './App.css';
import React from 'react';
class NumberField extends React.Component {
constructor(props) {
super(props);
this.state = { value: 0 };
}
changeHandler = event => {
event.persist();
let value = event.target.value;
this.setState(prevState => ({
item: { ...prevState.value, [event.target.value]: value }
}))
};
render() {
return (
<div>
<label for={this.props.label}>{this.props.labelName}</label>
<button onClick={this.decrement}>-</button>
<input type="number"
name={this.props.label}
id={this.props.label}
value={this.state.value}
onChange={this.changeHandler}>
</input>
<button onClick={this.increment}> </button>
</div>
);
}
}
class TextField extends React.Component {
constructor(props) {
super(props);
this.state = { value: "" };
}
render() {
return (
<div>
<label for={this.props.label}>{this.props.labelName}</label>
<input type="text" name={this.props.label} id={this.props.label} placeholder={this.props.placeholder}></input>
</div>
);
}
}
function handleSubmit(e) {
e.preventDefault();
console.log("Form Submitted");
// TODO Reset the state on all components so everything goes back to 0/Empty somehow
}
function App() {
return (
<div className="App">
<div className="AppForm">
<TextField labelName="Ferry Name" label="ferry_name" placeholder="Enter the ferry name" />
<div>
<NumberField labelName="Number of seats" label="seats" />
</div>
<div className="formSubmit">
<button onClick={handleSubmit}>Book Ferry</button>
</div>
</div>
</div>
);
}
export default App;
CodePudding user response:
Note: If you want to access component's state
inside a function, then you must
declare that function inside the component.
Other than that,
what you want to do can't be directly achievable by how you are handling child component's state
.
If you want to change the child component's state, the due to unidirectional nature
of react, you can't simply access the child's state.
What you can do is, you can have a
state = {number:0, text: ""}
inApp Component
and passupdate Functions
andfield values
asprops
to theChild Components
Another way (not recommended in react doc), if don't want to keep your state in Parent is, using
useImperativeHandle
. You can read about it in Link to docOne more way (recommended for larger projects), is to use
global state
managements likeredux
,context
, etc.
CodePudding user response:
As you mentioned you should send two more props, I named them reset
and changed
and also I changed your class components
to functional
const {useEffect,useState} = React;
const NumberField = (props) => {
const [value, setValue] = useState(0);
useEffect(() => {
if (props.reset) setValue(0);
}, [props.reset]);
const increment = () => {
setValue((value) => value 1);
};
const decrement = () => {
setValue((value) => value - 1);
};
const changeHandler = (event) => {
event.persist();
props.changed();
setValue(event.target.value);
//let value = event.target.value;
//setValue(prevState => ({
// item: { ...prevState.value, [event.target.value]: value //}
//}))
};
return (
<div>
<label for={props.label}>{props.labelName}</label>
<button onClick={decrement}>-</button>
<input
type="number"
name={props.label}
id={props.label}
value={value}
onChange={changeHandler}
></input>
<button onClick={increment}> </button>
</div>
);
};
const TextField = (props) => {
const [value, setValue] = useState("");
useEffect(() => {
if (props.reset) setValue("");
}, [props.reset]);
const handleChange = (event) => {
setValue(event.target.value);
props.changed();
};
return (
<div>
<label for={props.label}>{props.labelName}</label>
<input
value={value}
onChange={handleChange}
type="text"
name={props.label}
id={props.label}
placeholder={props.placeholder}
></input>
</div>
);
};
const App=()=> {
const [reset, setReset] = useState();
const handleSubmit = (e) => {
e.preventDefault();
console.log("Form Submitted");
setReset(true);
// TODO Reset the state on all components so everything goes back to 0/Empty somehow
};
const handleChanged = () => {
setReset(false);
};
return (
<div className="App">
<div className="AppForm">
<TextField
reset={reset}
changed={handleChanged}
labelName="Ferry Name"
label="ferry_name"
placeholder="Enter the ferry name"
/>
<div>
<NumberField
reset={reset}
changed={handleChanged}
labelName="Number of seats"
label="seats"
/>
</div>
<div className="formSubmit">
<button onClick={handleSubmit}>Book Ferry</button>
</div>
</div>
</div>
);
}
ReactDOM.render( <App/> ,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>