Reputation: 3792
In the below example, I am trying to do the following:
{ id: value, id: value, ...etc }
, I can then send this data structure to a service to do... whatever :)I am having problems with the implementation:
onChange
via setState which is typical to do in React. However, I also need to capture the changes made to the input fields.TLDR: I believe something is wrong with my use of set state, I am trying to set the state in the child, and in the parent via a callback function. However one is taking priority over the other, both set states are no executing. Why is this and how can implement this correctly?
Note: this is pseudocode, please forgive any typos made, I tried to keep it as real as possible.
class Submit extends React.Component {
constructor(props) {
super(props);
}
render() {
const { showButton } = this.props;
return (
<button type='button' disabled={!showButton}>
Hello world!
</button>
);
}
);
class Input extends React.Component {
constructor(props) {
super(props);
this.state = {
name: ''
};
}
handleChange = (e) => {
const { enable } = this.props;
const id = e.target.id;
const value = e.target.value;
this.setState({
[id]: value
});
enable(id, value); // <- Using this here breaks set state.
}
render() {
const { myName } = this.state;
return (
<div>
<input type='text' id='name' onChange={this.handleChange} placeholder='' />
<input type='text' id='address' onChange={this.handleChange} placeholder='' />
<!-- there can be more input fields -->
</div>
);
}
}
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
enableButton: false,
inputFieldValues: {},
};
}
enable = (value) => {
const { inputFieldValue } = this.state;
let changes = inputFieldValues || {};
changes[key] = value;
this.setState({
enableButton: true,
inputFieldValues: changes
});
}
render() {
const { enableButton } = this.state;
return (
<div>
<Input enable={this.enable} />
<Submit enableButton={enableButton} />
</div>
);
}
}
Upvotes: 0
Views: 57
Reputation: 484
I'm not quite sure that I've understood your problem, but here is fixed example of you pseudo-code.
What I've noticed:
const { inputFieldValue } = this.state;
let changes = inputFieldValues || {};
changes[key] = value;
I don't know whether you make the same mistake in your real app, but I want to mention that this is pretty rude mistake that can to an unexpected behavior, since you mutate the state object, instead of creating new one. React compares objects references, it doesn't make deep checks of them.
This let changes = inputFieldValues || {};
should be let changes = { ...inputFieldValues } || {};
.
Also, you didn't provide field values to your inputs. Although, it doesn't affect state changes, but then inputs and the state can become unsynchronized.
class Submit extends React.Component {
constructor(props) {
super(props);
}
render() {
const { enableButton } = this.props;
return (
<button type="button" disabled={!enableButton}>
Hello world!
</button>
);
}
}
class Input extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "",
address: ""
};
}
handleChange = e => {
const { enable } = this.props;
const id = e.target.id;
const value = e.target.value;
this.setState({
[id]: value
});
enable(id, value);
};
render() {
const { myName } = this.state;
console.log("Input:", this.state);
return (
<div>
<input
type="text"
id="name"
onChange={this.handleChange}
placeholder=""
{/* Always provide state values to your inputs to make sure they're always synchronized */}
value={this.state.name}
/>
<input
type="text"
id="address"
onChange={this.handleChange}
placeholder=""
value={this.state.address}
/>
</div>
);
}
}
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
enableButton: false,
inputFieldValues: {}
};
}
enable = (key, value) => {
const { inputFieldValues } = this.state;
// Copy objects, when you change their fields.
let changes = { ...inputFieldValues } || {};
changes[key] = value;
this.setState({
enableButton: true,
inputFieldValues: changes
});
};
render() {
const { enableButton } = this.state;
console.log("Parent:", this.state);
return (
<div>
<Input enable={this.enable} />
<Submit enableButton={enableButton} />
</div>
);
}
}
ReactDOM.render(<Parent />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Upvotes: 1
Reputation: 989
I'm not sure if you have an error in your code and it isn't reflected in the pseudocode you shared here, but based on it i could make it work, having state properly updated in both parent and children component (check the console.log ).
https://codesandbox.io/s/r79q9myj8o
Upvotes: 1