reactjs - Ako môžem pripojiť ref ku komponentu bez stavu v Reacte?


Chcem vytvoriť stateless komponent, ktorého input prvok môže byť validovaný rodičovským komponentom.

V mojom príklade nižšie narazím na problém, kde vstup ref sa nikdy nepriraďuje k súkromnej vlastnosti _emailAddress rodiča.

Keď sa zavolá handleSubmit, this._emailAddress je undefined. Chýba mi niečo, alebo existuje lepší spôsob, ako to urobiť?

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>
);

Odpoveď č. 1

Môžete použiť hák useRef, ktorý je dostupný od v16.7.0-alpha.

ÚPRAVA: Od verzie 16.8.0 sa odporúča používať Hooks v produkcii!

Hooky vám umožňujú udržiavať stav a spracovávať vedľajšie účinky vo funkčných komponentoch.

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>
    </>
  );
}

Prečítajte si viac v dokumentácii k APIs háčikov

Odpoveď č. 2

EDIT: Teraz to už môžete robiť s React Hooks. Pozrite si odpoveď od Ante Gulina.

Na stateless komponenty nemôžete pristupovať k metódam ako v Reacte (napr. componentDidMount, componentWillReceiveProps atď.), vrátane refs. Pozrite si túto diskusiu na GH pre celú konverzáciu.

Myšlienka bezstavového (stateless) je, že preň nie je vytvorená žiadna inštancia (stav). Preto nemôžete pripojiť ref, pretože neexistuje žiadny stav, ku ktorému by sa dal ref pripojiť.

Najlepšie by bolo odovzdať spätné volanie na prípad, keď sa komponent zmení, a potom priradiť tento text do stavu rodiča.

Alebo môžete úplne vynechať komponent bez stavu a použiť bežný triedny komponent.

Z dokumentov...

Atribút ref nemôžete používať na funkčných komponentoch, pretože nemajú inštancie. Môžete však použiť atribút ref vo vnútri renderovacej funkcie funkčného komponentu.

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>
  );  
}

Súvisiace články