I have an autocomplete field which uses
searchText = {this.state.searchText}
like this;
<AutoComplete
floatingLabelText='agent input'
ref='agentInput'
hintText="type response"
multiLine = {true}
fullWidth = {true}
searchText = {this.state.searchText}
onNewRequest={this.sendAgentInput}
dataSource={this.agentCommands}
/>
but when I update the
this.setState({searchText: null })
in the onNewRequest
func
it will clear the autoComplete once, but not the second time.
it seems some internal caching happens?
mat-ui components more general question:
Is there a way to call the methods on that object directly like setValue?
https://github.com/callemall/material-ui/blob/master/src/auto-complete.jsx#L244-L248
I tried something like
var field = (
<AutoComplete
searchText = {this.state.searchText}
dataSource={this.agentCommands}
/>
);
field.props.setValue("");
but that doesn't work. Given an instance of a component how would I access its methods?
this is a more general question, i could add it to the docs if someone could illuminate me.
how to call internal methods of the MUI components?
This is rather react related not material-ui
you cannot call methods on elements
rather on instances referenced with ref
, for more information please read through this awesome blog post by the react team here.
@alitaheri how would you suggest we get / set the ref
on the autocomplete input given the only API we have access to is <AutoComplete />
?
@joncursi Take a look at react's docs: https://facebook.github.io/react/docs/more-about-refs.html#a-complete-example
@alitaheri I guess what I'm trying to say is that Material UI does not expose the <input>
element for us to assign a ref
. It's bundled underneath the <AutoComplete />
component. How do we pass the ref through AutoComplete
to input
?
right right. You can't do that but you can use setValue
and getValue
the same way see here although calling them will warn you. I would advise against it too, you should follow react's idiomatic flow of data. use searchText
prop instead of calling imperative methods.
Hey, I am trying to use the props searchText
, and on onNewRequest
I set my searchText
to (empty string) but AutoComplete
still shows what the string was prior to me setting the searchText
What if we do something like this there:
const currentSearchText = this.state.searchText;
this.timerTouchTapCloseId = setTimeout(() => {
if(this.state.searchText === currentSearchText) {
this.setState({
searchText: searchText,
});
}
this.close();
this.timerTouchTapCloseId = null;
}, this.props.menuCloseDelay);
Can we just add a boolean prop that, when set to true, will prevent the asynchronous setState
inside handleItemTouchTap
?
Edit: actually, I don't think that solution would fully address the issue.
@alexprice91 explains the problem above. Even if you are controlling the AutoComplete
with the searchText
prop, that asynchronous setState
still gets fired. In that situation you end up with searchText
(the prop in a controlled use) being different than searchText
(the state), which is no bueno.
I don't really like the if(this.state.searchText === currentSearchText) {
solution, since it doesn't resolve the searchText
state and prop incongruency. I think we should just get rid of this setState
in its entirety. If the user wants to fill in the <input>
whenever an option is clicked, it's trivial for them to handle it themselves using onNewRequest
and the searchText
prop. We shouldn't be forcing this behavior considering A) how simple it is to implement in userland and B) how difficult / janky it is to override when it's baked in.
A short-term workaround is to give your auto complete component a ref, then manually call setState
to reset searchText
.
this.refs.autoComplete.setState({ searchText: ''})
Thanks @greypants! Your approach worked for me.
Even if you are controlling the AutoComplete with the searchText prop, that asynchronous setState still gets fired.
@jlroettger I completely agree, that setState
shouldn't be called at all when the component is controlled.
That issue has been discussed here https://github.com/callemall/material-ui/pull/5627.
However, In order not to introduce breaking change, I think that the following change would address the issue:
handleItemTouchTap = (event, child) => {
const dataSource = this.props.dataSource;
const index = parseInt(child.key, 10);
const chosenRequest = dataSource[index];
const searchText = this.chosenRequestText(chosenRequest);
+
+ this.setState({
+ searchText: searchText,
+ });
+ this.props.onUpdateInput(searchText, this.props.dataSource, {
+ type: 'selected',
+ });
this.timerTouchTapCloseId = setTimeout(() => {
this.timerTouchTapCloseId = null;
-
- this.setState({
- searchText: searchText,
- });
this.close();
this.props.onNewRequest(chosenRequest, index);
}, this.props.menuCloseDelay);
};
For some reason, this issue still persisted for me. There are different arguments to the third parameter depending on whether you're typing or selecting a menu item. I just honed in on that action to only set the state when it is a change event
const handleUpdateInput = (attributeName, _, { source }) => {
if (source === 'change') {
this.setState({ attributeName })
}
}
As the components are now functional, setState is no longer working, do we have any alternative solution?
@sirajalam049 Material-UI can still be used in class components, only our demos can't. This is very handy for the legacy parts of your codebase so you don't have to migrate them to hooks (assuming you write all new features in hooks).
Most helpful comment
Can we just add a boolean prop that, when set to true, will prevent the asynchronoussetState
insidehandleItemTouchTap
?Edit: actually, I don't think that solution would fully address the issue.
@alexprice91 explains the problem above. Even if you are controlling the
AutoComplete
with thesearchText
prop, that asynchronoussetState
still gets fired. In that situation you end up withsearchText
(the prop in a controlled use) being different thansearchText
(the state), which is no bueno.I don't really like the
if(this.state.searchText === currentSearchText) {
solution, since it doesn't resolve thesearchText
state and prop incongruency. I think we should just get rid of thissetState
in its entirety. If the user wants to fill in the<input>
whenever an option is clicked, it's trivial for them to handle it themselves usingonNewRequest
and thesearchText
prop. We shouldn't be forcing this behavior considering A) how simple it is to implement in userland and B) how difficult / janky it is to override when it's baked in.