I want to implement an X icon inside Input ponent that will clear the input field. I can easily do it if I control the state. But is it actually possible with stateless ponent? I use react-semantic-ui, their stateful ponents have auto controlled state.
So I want to create an input that can be used like this:
//Controlled
class App extends React.Component {
state = {
value:''
}
onChange = (event, props) => {
this.setState({value: props.value});
}
onClearInput = () => {
this.setState({value: ''});
}
render() {
return (
<MyInput
clearable
value={this.state.value}
onChange={this.onChange}
onClearInput={this.onClearInput}
/>
)
}
}
I want to implement an X icon inside Input ponent that will clear the input field. I can easily do it if I control the state. But is it actually possible with stateless ponent? I use react-semantic-ui, their stateful ponents have auto controlled state.
So I want to create an input that can be used like this:
//Controlled
class App extends React.Component {
state = {
value:''
}
onChange = (event, props) => {
this.setState({value: props.value});
}
onClearInput = () => {
this.setState({value: ''});
}
render() {
return (
<MyInput
clearable
value={this.state.value}
onChange={this.onChange}
onClearInput={this.onClearInput}
/>
)
}
}
Or
// Uncontrolled
class App extends React.Component {
onChange = (event, props) => {
doSomething(props.value);
}
render() {
return (
<MyInput
clearable
onChange={this.onChange}
/>
)
}
}
In the second example, clearable
feature will not work because we're not controlling the value.
MyInput
can be implemented like this:
import React from 'react';
import { Input } from 'semantic-ui-react';
import ClearIcon from './ClearIcon';
function MyInput(props) {
const prepareProps = {...props};
if (props.clearable) {
prepareProps.icon=<ClearIcon onClick={props.onClearInput} />;
delete prepareProps.clearable;
}
delete prepareProps.onClearInput;
return (
<div className="my-input">
<Input {...prepareProps} />
</div>
);
}
...etc.
My problems:
clearable
feature must work in both controlled and uncontrolled manner.clearable
feature should not require a handler. It would be nice to just provide a prop and handle the render and behavior of the X button under the hood.
I don't see any way to make this work. Any ideas?
Share Improve this question asked Mar 26, 2018 at 12:32 artemeanartemean 8551 gold badge10 silver badges25 bronze badges 12- Why does it have to work on uncontrolled inputs? – trixn Commented Mar 26, 2018 at 12:44
-
@trixn, why not? :-) I just want to create a versatile ponent without forcing people to use it in any specific way. So if you just put
<MyInput clearable />
in your app you will have an input with X button that will just work out of the box. I don't think it's possible, but maybe I'm missing something. That's why I asked the question. – artemean Commented Mar 26, 2018 at 12:54 - Yeah but if you write the ponent that gets used by somebody else, why should they care if it internally uses a controlled or an uncontrolled input? I don't understand the problem. – trixn Commented Mar 26, 2018 at 12:56
-
I agree with @trixn. You can use render props reactjs/docs/render-props.html, this will let the person using your ponent consume your controlled props into their own view or just control the input. The only other scenario I can see, is that the user of your ponent will have to pass you a
ref
to their input. – pkuzhel Commented Mar 26, 2018 at 13:16 -
Right, people should not care what I do internally. But they should be able to use the ponent both controlled/uncontrolled way. The problem is that I cannot control
value
internally because then users won't be able to set their ownvalue
. On the other hand, if I don't control thevalue
I cannot clear it. @pkuzhel I don't see how render prop can help me here. Can you explain, please? – artemean Commented Mar 26, 2018 at 13:38
2 Answers
Reset to default 3Allowing the user of your ponent to set the value via props and still being able to clear the input can be easily achieved, e.g. like this:
class MyInput extends React.Component {
constructor(props) {
super(props);
this.state = {value: props.value || ''};
}
handleChange = event => {
const { onChange } = this.props;
this.setState({ value: event.currentTarget.value });
onChange && onChange(event);
};
handleClear = () => {
const { onClearInput } = this.props;
this.setState({ value: "" });
onClearInput && onClearInput();
};
render() {
const { value } = this.state;
const { clearable, onChange, ...inputProps } = this.props;
const clearIcon = clearable && <ClearIcon onClick={this.handleClear} />;
return (
<div className="my-input">
<Input value={value} icon={clearIcon} onChange={this.handleChange} {...inputProps} />
</div>
);
}
}
You could even make it more posable by using an hoc or render props as proposed by @pkuzhel.
Look at this codesandbox example to see it in action.
@Andrey
Would you try this below code? and let me know if that resolves your issue.
import React, { Component } from 'react';
import { Input, Button } from 'semantic-ui-react'
class App extends Component {
clear = () => {
console.log(this.inputRef.target.value);
this.inputRef.target.value = '';
}
render() {
return (
<div className="App">
<Input placeholder='Search...' onChange={(input) => {input.persist(); this.inputRef = input}} />
<Button onClick={this.clear}>Clear</Button>
</div>
);
}
}