Reputation:
I have an input field component that meets these conditions:
Upon first focus, nothing happens until the field is valid, then a valid class is applied
Upon first blur, if the field is invalid, apply an invalid class.
After the first blur, upon any further engagement with the field, a class is applied whenever the value of the field changes from valid to invalid or vice versa.
To achieve this I have done this:
import React, { Component } from "react";
class Input extends Component {
constructor(props) {
super(props);
this.state = {
touched: false,
valid: false,
focused: false,
value: ""
};
this.handleFocus = this.handleFocus.bind(this);
this.handleBlur = this.handleBlur.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleFocus() {}
handleBlur() {
if (!this.state.touched) {
this.setState({
touched: true
});
} else if (this.state.touched) {
this.setState({
focused: true
});
}
}
handleChange(e) {
const val = e.target.value
this.setState({ value: val }, () => {
this.validateField();
}
);
}
validateField() {
const touched = this.state.touched;
const focused = this.state.focused;
const valid = this.state.valid;
const value = this.state.value;
if (value.length >= 5) {
this.setState({
valid: true,
touched: true
});
} else {
this.setState({ valid: false });
}
}
render() {
return (
<div>
<input
id={this.props.id}
name={this.props.name}
type="text"
className={`form-control ${styles["kyi-input"]} ${
this.state.valid ? "is-valid" : ""
} ${this.state.touched && !this.state.valid ? "is-invalid" : ""}`}
required
spellCheck="false"
autoComplete="off"
onFocus={this.handleFocus}
onChange={this.handleChange}
value={this.state.value}
onBlur={this.handleBlur}
placeholder={this.props.placeholder}
/>
</div>
);
}
}
class Parent extends Component {
handleInput(val, name) {
// Can get value of input here
this.setState({
[name]: val
});
}
render() {
<Input placeholder="Test" onChange={(val) => {this.handleInput(val, 'inputName')}}/>
}
}
<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>
It works, but this means that the state of the field lives in the child component and not the parent.
The input field's onBlur function is reliant on the state of the field.
Is there a way to refactor this so that the input state lives in the parent component while the onBlur function lives in the child component?
Upvotes: 1
Views: 213
Reputation: 1073
I think you should get all your State in the Parent component, you should also get all the functions that modify it in the Parent Component. This would allow you to have a 'single source of truth' that keeps track of state's changes and pass it to all your child components. Check out Lifting state up
Upvotes: 2