How do I set the value of a Reactstrap Input to be empty? I am using code like this.
handleChange = (event) => {
this.setState({message: event.target.value});
};
< Input onChange = {this.handleChange}/>
Also, what is the best practice for getting the value of an input: refs or onChange?
You gotta set a value property for your input which holds the value of your input, so your input looks like this:
<Input value={this.state.message} onChange={this.handleChange} />
and then when you want to clear its value, you just do this:
this.setState({message: ''})
and for your other question, the answer is that the Refs provide a way to access DOM nodes or React elements created in the render method, according to React documentation You can use Refs when:
Managing focus, text selection, or media playback.
Triggering imperative animations.
Integrating with third-party DOM libraries.
and you have to AVOID using refs for anything that can be done declaratively.
Then, here we just use onChange because we don't simply need Refs!
You need to assign state value to your input field.
public class myApp() extends React.Component {
constructor(props){
super(props);
this.state = {
message: ''
};
}
handleChange = (event) => {
this.setState({message: event.target.value});
};
render() {
return (
<Input value={this.state.message} onChange={this.handleChange} />
);
}
}
Related
Hyall
Can you please point out bad practices / mistakes in the code below?
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
title: "default title"
};
this.inputTxt = this.state.title;
this.myRef = React.createRef();
}
componentDidMount() {
this.myRef.current.value = this.inputTxt;
}
handleSubmit = e => {
e.preventDefault();
console.log("submitted");
this.setState({ ...this.state, title: this.inputTxt });
};
handleInput = e => {
this.inputTxt = e.target.value;
};
render() {
return (
<>
<div>{this.state.title}</div>
<form onSubmit={this.handleSubmit}>
<input
type="text"
onChange={this.handleInput}
ref={this.myRef}
></input>
<button type="submit">Save</button>
<button type="reset">Reset</button>
</form>
</>
);
}
}
And some special questions:
is it ok to use this.somevar properties of component class to store variables' values? how to avoid naming collisions?
is it normal to use refs to set input's value?
if I want to set onChange and value bound to reactive variable in one input control, it will freeze? how to gain [(ngModel)] Angular-like control over input element?
It seems like you're over complicating things. I don't see a need for refs here. I don't think setting a class property will trigger a re-render, so this way of managing input might not work at all regardless of it not being a best practice.
Just use state as the value, and update state on change. To keep things flexible, use the input's name as the state key. Something like this:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
title: "default title"
};
}
handleSubmit = e => {
e.preventDefault();
console.log("submitted");
// Not sure if thats what you're looking for..
// Also: no need to do {...this.state, }. setState does a merge, not overwrite
this.setState({ title: this.state.input1 });
};
handleChange = e => {
// Use e.target.name as the computed property name,
// so it can be used for infinite number of inputs
this.setState({[e.target.name]: e.target.value});
};
render() {
return (
<>
<div>{this.state.title}</div>
<form onSubmit={this.handleSubmit}>
<input
type="text"
name="input1" // Give it a unique name for setting state
value={this.state.input1} // Specify the value instead of using a ref
onChange={this.handleChange}
></input>
<button type="submit">Save</button>
<button type="reset">Reset</button>
</form>
</>
);
}
}
Here is the link to the react docs on refs.
The primary they recommend use-cases are:
Managing focus, text selection, or media playback.
Triggering imperative animations.
Integrating with third-party DOM libraries.
Which I don't believe apply, here. So I wouldn't recommend using them here.
I came across the arrow function feature being used as Class property in React component. Looking online I found that it makes code more readable and because of the arrow function features we do not have to bind the handlEvents function inside of constructor.
I still have to use the bind method even while using an arrow function for class property as shown in the code below. When i remove the binding in constructor it shows error in console Warning: A component is changing an uncontrolled input of type text to be controlled. and the form errors do not show up as well
class Contact extends Component {
constructor(props) {
super(props);
this.handleBlur = this.handleBlur(this);
}
handleBlur = evt => field => {
this.setState({
touched: { ...this.state.touched, [field]: true }
});
render() {
return(
<Form onSubmit={this.handleSubmit}>
<FormGroup row>
<Label htmlFor="firstname" md={2}>
First Name
</Label>
<Col md={10}>
<Input
type="text"
id="firstname"
name="firstname"
placeholder="First Name"
valid={errors.firstname === ""}
invalid={errors.firstname !== ""}
value={this.state.firstname}
onBlur={event => {
this.handleBlur("firstname");
}}
onChange={this.handleInputChange}
/>
<FormFeedback>{errors.firstname}</FormFeedback>
</Col>
</FormGroup>
</Form>
)
}
Arrow functions for early bindings in classes are not officially supported by the current ECMAScript.
Using arrow functions as class methods will get you in trouble when your class is inherited and the child wants to override a parent method.
However, I would say it is pretty safe to use them in your react components as you will not get into trouble with inheritance here, since with react you usually will not further inherit from your own components (see Composition vs Inheritance):
At Facebook, we use React in thousands of components, and we haven’t found any use cases where we would recommend creating component inheritance hierarchies.
Dan Abramov is using arrow functions in component methods as well, however he recommends only to use it if early binding is required.
While it’s still experimental, in my experience it solves the problem fairly nicely. It’s not at all React-specific: I find it useful in any classes that deal with asynchrony and callbacks because the binding problem is common for all JavaScript, not just React. We enabled this syntax proposal in the whole Facebook codebase, and if it gets dropped or changes, we’ll make sure to release an automated codemod to migrate to the new syntax (or, worst case, transform it back into bind calls in constructor).
However as Dan notes, to be on the safe site, stick to early binding in constructors:
If you want to stick to the language standard, manual binding in
constructor is the way to go. It’s tedious but usually you only want
to do this for event handlers, and by convention you start them with
handle* in React, so it’s not too hard to remember to bind those.
Update: regarding your case:
In your case you can either use the solution provided by Anshul Bansal where you pass the fieldname into your handleBlur and make use of the field variable in your closure when you pass the returned function as event callback.
Or you can directly acces the input name of the field via the evt.target (code not tested).
handleBlur = evt => {
const field = evt.target.name;
this.setState({
touched: { ...this.state.touched, [field]: true }
});
You need to change the function a little bit as follow.
class Contact extends Component {
constructor(props) {
super(props);
this.handleBlur = this.handleBlur(this);
}
handleBlur = field => () => {
this.setState({
touched: { ...this.state.touched, [field]: true }
});
render() {
return(
<Form onSubmit={this.handleSubmit}>
<FormGroup row>
<Label htmlFor="firstname" md={2}>
First Name
</Label>
<Col md={10}>
<Input
type="text"
id="firstname"
name="firstname"
placeholder="First Name"
valid={errors.firstname === ""}
invalid={errors.firstname !== ""}
value={this.state.firstname}
onBlur={this.handleBlur("firstname")}
onChange={this.handleInputChange}
/>
<FormFeedback>{errors.firstname}</FormFeedback>
</Col>
</FormGroup>
</Form>
)
}
I would not do it with an arrow function, but you can. I will explain the two methods (there are a few more), the first is the one that I use normally.
Binding with a higher order function (or method)
It is simply a method that returns the event callback, as this is a method is already bound to this. This way you can pass any arguments to the method that is a closure, and these arguments will be present in the callback. That is the case of the field argument. Note that I switched the order of the argument, field should be first because it is called first to return the callback.
handleBlur(field) {
return evt => {
console.log(this.state);
this.setState({
touched: { ...this.state.touched,
[field]: true
}
});
};
}
And you can bind it simply with:
onBlur = {this.handleBlur("firstname")}
This has the advantage that you do not need to bind to this in the constructor.
Using an arrow function
The code is similar, but you have to bind to this in the constructor.
handleBlurArrow = field => evt => {
console.log(this.state);
this.setState({
touched: { ...this.state.touched,
[field]: true
}
});
};
Binding:
onBlur = {this.handleBlurArrow("firstnameArrow")}
Bind this on constructor:
this.handleBlurArrow = this.handleBlurArrow.bind(this);
Working example
class Contact extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.handleBlurArrow = this.handleBlurArrow.bind(this);
}
handleBlurArrow = field => evt => {
console.log(this.state);
this.setState({
touched: { ...this.state.touched,
[field]: true
}
});
};
handleBlur(field) {
return evt => {
console.log(this.state);
this.setState({
touched: { ...this.state.touched,
[field]: true
}
});
};
}
render() {
return (<div>
<input type = "text" id = "firstname"
name = "firstname"
placeholder = "First Name"
value = {this.state.firstname}
onBlur = {this.handleBlur("firstname")}
onChange = {this.handleInputChange}
/>
<input type = "text" id = "firstnameArrow"
name = "firstname"
placeholder = "First Name Arrow"
value = {this.state.firstname}
onBlur = {this.handleBlurArrow("firstnameArrow")}
onChange = {this.handleInputChange}
/>
</div>
)
}
}
ReactDOM.render( <Contact /> ,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
I am developing a React JS application. What I am doing now is I am fetching data asynchronously from the server and render the values in the TextField. I know how to do it and my approach is working as well. But, I just do not like my current approach.
This is the working approach
class TestComponent extends React.Component {
constructor(props)
{
super(props);
this.fetchName = this.fetchName.bind(this);
this.handleChange = this.handleChange.bind(this);
this.state = {
name : ''
}
}
fetchName()
{
//get the name asynchronously from the server. I am using Axios
this.setState({ name : nameValueFromTheServer })
}
handleChange(e)
{
this.setState({ name : e.target.value })
}
render()
{
return (
<MuiThemeProvider>
<div>
<TextField onChange={this.handleChange} label="Name" value={this.state.name} />
</div>
</MuiThemeProvider>
)
}
}
The thing I do not like about above approach is that I have to implement handleChange method to retrieve the value of the input value. If I do not implement it, I cannot change the name input value because the state value is not changed. To retrieve a simple input value, I have to write extra lines of code. In jQuery, I just retrieve the input value like this, $(selector).val(). Without implementing the handleChange method, I can use the ref like this.
<TextField inputRedf={(input) => this.tfName = input } label="Name" />
Then I retrieve the value dynamically like this.
this.tfName.value
The problem with using the reference is setting the default value which is fetched asynchronously from the server.
I can set the default value like this to the TextField
<TextField inputRedf={(input) => this.tfName = input } defaultValue={this.state.name} label="Name" />
Pay attention to the defaultValue attribute in the above code. When I set the value using defaultValue, the initial value of the name state will be set to the text field. But we can still change the input value of the name typing in from the UI even if we do not implement the handleChange event. But the problem is that I am getting the data asynchronously and setting the this.state.name dynamically.
So in the component constructor, the name state is empty. Then I set it in the callback of the asynchronous call. But the defaultValue can be set only once. So the input field is always showing empty. What I like to know is, how can I set the defaultValue of the TextField dynamically? The reason I am using ref is that I do not want to implement the onChange event as well to track state the reset the input value. If I could set the defaultValue dynamically, I will just the value dynamically in the callback of the asynchronous call. What is the best solution to simplify this scenario?
You don't need default value actually. If you want to avoid using onChange handler you can imperatively set input value in async callback:
class TestComponent extends React.Component {
constructor(props) {
super(props);
this.fetchName = this.fetchName.bind(this);
this.handleChange = this.handleChange.bind(this);
}
fetchName() {
if(this.tfName.value == '') {
// only update if user have not changed the input value.
this.tfName.value = nameValueFromTheServer;
}
}
render() {
return (
<MuiThemeProvider>
<div>
<TextField
inputRef={(input) => this.tfName = input }
label="Name"/>
</div>
</MuiThemeProvider>
);
}
}
I'm building a React application and I want to test certain functionality, however, I'm not sure how I should test it.
First of all I'm using React and ReactDOM version 15.4.2
I have a component which represents an input button.
class InnovanaInputBox extends React.Component {
constructor(props) {
super(props);
this.state = this.initializeState();
// Bind all the event handlers.
this.onChange = this.onChange.bind(this);
}
initializeState() {
return {
hasValue: false
}
}
onChange(event) {
this.setState(
{
hasValue: event.target.value !== ""
}
);
}
render() {
return (
<div className={"innovana-input-box" +
(typeof(this.props.className) !== typeof(undefined) &&
this.props.className !== "" ? " " + this.props.className: "") +
(this.state.hasValue ? " value" : "")}>
<input type="text" onChange={this.onChange} />
<label>{this.props.label}</label>
</div>
);
}
}
InnovanaInputBox.PropTypes = {
label: React.PropTypes.string.isRequired
}
export default InnovanaInputBox;
So, when I do enter a value in the input box inside the component, the state hasValue does change to true if the input box does contain a value.
In the render method, an additional class named value it set on the container component.
Now, how can I test this specific behaviour?
I have Karma and Mocha setup and I'm using the react-addons-test-utils version 15.4.2.
I do already have some basic tests to see if the component renders, but testing this seems a bit difficult.
I'm trying to play with Simulate and findReferedDOMComponentWithClass but I don't get it.
Any advice on how this can be tested?
Kind regads
you aren't specifying a ref on the class, so another way to get the element to test if an element has a class is to go about it like this.
const input = document.getElementsByClassName('innovana-input-box')[0];
input.classList.contains('value'); // true
Now if there is more than one you may want to either specify an id on the element and use document.getElementById() instead. or add a ref to the input and use that
More about refs here
EDIT:
if you want to test the state value on the component you can do something like this
const inputBox = TestUtils.renderIntoDocument(<InnovanaInputBox />);
const input = React.findDOMNode(inputBox).querySelector('input');
input.value = 'some updated value';
TestUtils.Simulate.change(input);
inputBox.state.hasValue // true
I have a component called SearchInput and it has in it
<input
type='text'
className='input-field'
value={value}
placeholder={this.state.placeholder}
// onFocus={::this.onFocus}
// onBlur={::this.onBlur}
// onKeyUp={::this.onKeyUp}
// onKeyDown={::this.hanleArrowKeys}
// onChange={::this.onChange}
/>
However, when I type anything into it, nothing happens. The text doesn't even appear. What am I doing wrong?
Probably your state is not updating, maybe didn't you bind "this" to function onChange?
Here is an example of correct input in react:
class SearchInput extends Component {
constructor(props) {
super(props);
this.state = { value: '' };
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(event) {
this.setState({ value: event.target.value });
}
render() {
return <input type="text" value={this.state.value} onChange={this.handleInputChange}/>;
}
}
Probably you are binding the value of the input box with an attribute in the state of the component and you are either not providing an onChange prop to the input tag or your onChange callback method is not updating the attribute in the state to which the input tag's value is bound.