Semantic-ui-react: Form.Input stateless function cannot be given refs.

Created on 26 Dec 2017  Â·  20Comments  Â·  Source: Semantic-Org/Semantic-UI-React

✖ CSS ISSUES → Post on https://github.com/Semantic-Org/Semantic-UI

✖ USAGE QUESTIONS → Use these dedicated resources:
Docs - http://react.semantic-ui.com
Chat - https://gitter.im/Semantic-Org/Semantic-UI-React
SO - https://stackoverflow.com/questions/tagged/semantic-ui-react?sort=votes

✔ BUGS → This form is required:

Steps

<Form.Input  ref="name"
    onChange={this.onChange.bind(this)} 
    required autoFocus />
this.ref.name.value = "";

Expected Result

ref.name.value should work.

Actual Result

Warning: Stateless function components cannot be given refs (See ref "name" in FormInput created by Register). Attempts to access this ref will fail.

Version

0.77.1

Testcase

wontfix

Most helpful comment

@layershifter wrapping it in the Ref component gives you the ref of a div, not the actual input. I think this should be reopened

All 20 comments

You can wrap any your component to Ref, it will return a real DOM node.

However, I dont see any need to use refs there. Use controlled components, pass your value with value prop:

<Form.Input value={value} />

I first used refs, then i used another way to get onChange.value. Just thought it should be added though. Thank for letting me know.

@layershifter wrapping it in the Ref component gives you the ref of a div, not the actual input. I think this should be reopened

@haikyuu can you please open an issue specifying your use case and why using controlled components will not work for you?

Ok, here is one.

There is a bug with the way different browser handle auto-filled inputs, and thus an input would seem to be filled to the user but React won't be notified and your state won't match the browser's.

One solution for this is to use uncontrolled components.

I'm sure there are other use cases as well.

@layershifter @levithomason This may be a vaild use case. Thoughts?

There is a bug with the way different browser handle auto-filled inputs, and thus an input would seem to be filled to the user but React won't be notified and your state won't match the browser's.

This seems more like a React core issue to me than a SUIR issue. React explicitly does not handle DOM manipulations made outside of React. Example, setting the value of an input is not supported.

I think the scope of this need is beyond both the scope of React and SUIR.

Thanks @levithomason. Per the above feedback, re-closing this issue.

I ran into this same limitation. My use case is wanting to call focus() on the input field after an event, for example, after adding a new row of inputs or on a validation error. I agree with @haikyuu, <Ref> should give ref to the input, not the surrounding <div>. Thoughts? For now I am working around this.

@snardone the input instance offers a focus method for this purpose. It is a common best practice to offer this method for Input components:

https://react.semantic-ui.com/elements/input#input-example-ref-focus

Thank you, this allows me to assign a ref to call focus() and automatically get the <div class='ui input'> wrapper, which I was doing manually with a raw input tag. Which is great. But now it's unclear why <Form.Input> shouldn't have the same ref functionality as <Input>, i.e. the original issue of this thread?

@levithomason i understand you do not want to expose refs in your components. But using the library's Ref component gives me the ref of the parent div.
And i have to manually look for where my input is in the dom tree. And this depends on the props of Input.
To elaborate, here is the hack i am using

// This is a wrapper that gives you access to ref
// inside a Form.Input component
// Should be used this way
// <FormInput innerRef={ref=> ...}/>
// the returned ref is the input's reference
export default class FormInput extends React.Component {
  static propTypes = {
    innerRef: PropTypes.func,
  }
  constructor(props) {
    super(props)
  }
  innerRefHandler = reference => {
    // should be used normally --> ref={ref=> this.input = ref}
    const { innerRef } = this.props
    const isInput = ({ nodeName }) => nodeName === 'INPUT'

    for (let i = 0; i < reference.children.length; i++) {
      if (isInput(reference.children[i])) {
        return innerRef(reference.children[i])
      } else {
        //check children
        for (let j = 0; j < reference.children[i].children.length; j++) {
          if (isInput(reference.children[i].children[j])) {
            return innerRef(reference.children[i].children[j])
          }
        }
      }
    }
  }
  render() {
    const { innerRef, ...props } = this.props
    if (!innerRef) {
      return <Form.Input {...props} />
    } else {
      return (
        <Ref innerRef={this.innerRefHandler}>
          <Form.Input {...props} />
        </Ref>
      )
    }
  }
}

It's clearly a hack, but it's the only thing i came up with so far.

I think the scope of this need is beyond both the scope of React and SUIR.

Attaching a ref is inside the scope of React, and using Ref is the semantic-ui way. But there are limitations in the actual implementation.

For anybody who found this and is looking for a way to get a Form.Input to focus when opening a modal, here is another solution: https://codepen.io/inergy/pen/JvOjYb

A workaround for focusing an input below React 16.3 with the oldskool way

<Form.Input id="field" />

const id = 'field';
const element = document.querySelector(`#${id}`);
if (element) element.focus();

I have encountered this bug as well, and cannot see why the Form.Input should have different handling than the Input-component.

@Karl-Stefan Form.Input wraps the input in a form field, eg:

<div class="field">
  <label>First Name</label>
  <input type="text" name="first-name" placeholder="First Name">
</div>

Thus, the ref to the first element would be the div, whereas the Input component is only the input element.

I'd like to mention another use case that is to integrate with react-hook-form https://github.com/react-hook-form/react-hook-form/issues/85
This is just a nice-to-have as Form.Field could be used instead

Found this for working with semantic form and react-hook-form: https://codesandbox.io/embed/semantic-ui-react-form-hooks-vnyjh

I encountered this issue also, would be great if you could do forwardRef

We have a dedicated issue for this #3819.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

devsli picture devsli  Â·  3Comments

jayphelps picture jayphelps  Â·  3Comments

KevinGorjan picture KevinGorjan  Â·  3Comments

levithomason picture levithomason  Â·  3Comments

AlvMF1 picture AlvMF1  Â·  3Comments