Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I attach to a stateless component's ref in React?

I am looking to create a stateless component who's input element can be validated by the parent component.

In my example below, I am running into a problem where the input ref is never being assigned to the parent's private _emailAddress property.

When handleSubmit is called, this._emailAddress is undefined. Is there something I'm missing, or is there a better way to do this?

interface FormTestState {     errors: string; }  class FormTest extends React.Component<void, FormTestState> {     componentWillMount() {         this.setState({ errors: '' });     }      render(): JSX.Element {         return (             <main role='main' className='about_us'>                              <form onSubmit={this._handleSubmit.bind(this)}>                     <TextInput                          label='email'                         inputName='txtInput'                         ariaLabel='email'                         validation={this.state.errors}                         ref={r => this._emailAddress = r}                     />                      <button type='submit'>submit</button>                 </form>             </main>         );     }      private _emailAddress: HTMLInputElement;      private _handleSubmit(event: Event): void {         event.preventDefault();         // this._emailAddress is undefined         if (!Validators.isEmail(this._emailAddress.value)) {             this.setState({ errors: 'Please enter an email address.' });         } else {             this.setState({ errors: 'All Good.' });         }     } }  const TextInput = ({ label, inputName, ariaLabel, validation, ref }: { label: string; inputName: string; ariaLabel: string; validation?: string; ref: (ref: HTMLInputElement) => void }) => (     <div>         <label htmlFor='txt_register_first_name'>             { label }         </label>          <input type='text' id={inputName} name={inputName} className='input ' aria-label={ariaLabel} ref={ref} />          <div className='input_validation'>             <span>{validation}</span>         </div>     </div> ); 
like image 326
drewwyatt Avatar asked Dec 08 '16 20:12

drewwyatt


People also ask

How do you pass ref in functional components?

To create a ref in a functional component we use the useRef() hook which returns a mutable object with a . current property set to the initialValue we passed to the hook. This returned object will persist for the full lifetime of the component. Thus, throughout all of its re-rendering and until it unmounts.

How do you pass ref as props in React?

React passes the ref to the (props, ref) => ... function inside forwardRef as a second argument. We forward this ref argument down to <button ref={ref}> by specifying it as a JSX attribute. When the ref is attached, ref.

How do you access the DOM element in React?

In React we can access the DOM element using Refs. Refs provide a way to access DOM nodes or React elements created in the render method. Creating Refs: Refs are created using React. createRef() and attached to React elements via the ref attribute.


2 Answers

You can useuseRef hook which is available since v16.7.0-alpha.

EDIT: You're encouraged to use Hooks in production as of 16.8.0 release!

Hooks enable you to maintain state and handle side effects in functional components.

function TextInputWithFocusButton() {   const inputEl = useRef(null);   const onButtonClick = () => {     // `current` points to the mounted text input element     inputEl.current.focus();   };   return (     <>       <input ref={inputEl} type="text" />       <button onClick={onButtonClick}>Focus the input</button>     </>   ); } 

Read more in Hooks API documentation

like image 146
Ante Gulin Avatar answered Sep 21 '22 10:09

Ante Gulin


EDIT: You now can with React Hooks. See the answer by Ante Gulin.

You can't access React like methods (like componentDidMount, componentWillReceiveProps, etc) on stateless components, including refs. Checkout this discussion on GH for the full convo.

The idea of stateless is that there isn't an instance created for it (state). As such, you can't attach a ref, since there's no state to attach the ref to.

Your best bet would be to pass in a callback for when the component changes and then assign that text to the parent's state.

Or, you can forego the stateless component altogether and use an normal class component.

From the docs...

You may not use the ref attribute on functional components because they don't have instances. You can, however, use the ref attribute inside the render function of a functional component.

function CustomTextInput(props) {   // textInput must be declared here so the ref callback can refer to it   let textInput = null;    function handleClick() {     textInput.focus();   }    return (     <div>       <input         type="text"         ref={(input) => { textInput = input; }} />       <input         type="button"         value="Focus the text input"         onClick={handleClick}       />     </div>   );   } 
like image 44
BradByte Avatar answered Sep 20 '22 10:09

BradByte