React.forwardRef, sınıf tabanlı bir bileşende nasıl kullanılır?


113

React.forwardRef'i kullanmaya çalışıyorum, ancak sınıf tabanlı bir bileşende (HOC değil) nasıl çalıştırılacağına bakıyorum.

Dokümanlar örnekleri, öğeleri ve işlevsel bileşenleri kullanır, hatta sınıfları daha yüksek düzey bileşenler için işlevlere sarar.

Yani, böyle bir şey ile başlayan bu onların içinde ref.jsdosyanın:

const TextInput = React.forwardRef(
    (props, ref) => (<input type="text" placeholder="Hello World" ref={ref} />)
);

ve bunun yerine şu şekilde tanımlıyoruz:

class TextInput extends React.Component {
  render() {
    let { props, ref } = React.forwardRef((props, ref) => ({ props, ref }));
    return <input type="text" placeholder="Hello World" ref={ref} />;
  }
}

veya

class TextInput extends React.Component {
  render() { 
    return (
      React.forwardRef((props, ref) => (<input type="text" placeholder="Hello World" ref={ref} />))
    );
  }
}

sadece çalışıyor: /

Ayrıca, biliyorum, ref tepki yolu değil. Üçüncü taraf bir tuval kitaplığı kullanmaya çalışıyorum ve bazı araçlarını ayrı bileşenlere eklemek istiyorum, bu nedenle olay dinleyicilere ihtiyacım var, bu yüzden yaşam döngüsü yöntemlerine ihtiyacım var. Daha sonra farklı bir rotaya gidebilir, ancak bunu denemek istiyorum.

Doktorlar bunun mümkün olduğunu söylüyor!

Referans yönlendirme, DOM bileşenleriyle sınırlı değildir. Referansları da sınıf bileşen örneklerine iletebilirsiniz.

dan bu bölümde notu.

Ama sonra sadece sınıflar yerine HOC'leri kullanmaya devam ediyorlar.

Yanıtlar:


108

Her zaman için aynı pervaneyi kullanma fikri, refsınıf dışa aktarımı için bir yardımcı ile proxy yapılarak elde edilebilir.

class ElemComponent extends Component {
  render() {
    return (
      <div ref={this.props.innerRef}>
        Div has ref
      </div>
    )
  }
}

export default React.forwardRef((props, ref) => <ElemComponent 
  innerRef={ref} {...props}
/>);

Yani temelde, evet, referansı ilerletmek için farklı bir pervaneye sahip olmak zorundayız, ancak bu merkez altında yapılabilir. Halkın bunu normal bir referans olarak kullanması önemlidir.


4
Bileşeniniz React- connectRedux'lar veya marterial-UI'ler gibi bir HOC'ye sarılmışsa ne yaparsınız withStyles?
J. Hesters

connectVeya ile ilgili sorun nedir withStyles? Tüm HOC'leri forwardRefzincirdeki en düşük bileşene bir ref geçirmek için "güvenli" destek ile sarmalı ve dahili olarak kullanmalısınız.
Mr Br

SetState kullanırken bunu Enzyme'de nasıl test edeceğinize dair bir fikir var mı?
zero_cool

Üzgünüm biraz daha detaya ihtiyacım var. Tam olarak sorunun ne olduğundan emin değilim.
Mr Br

2
Alıyorum: Değişmez İhlal: Nesneler bir React çocuğu olarak geçerli değil (bulunan: {$$ typeof, render} anahtarlarına sahip nesne). Bir çocuk koleksiyonu oluşturmak istiyorsanız, bunun yerine bir dizi kullanın.
Brian Loughnane

9
class BeautifulInput extends React.Component {
  const { innerRef, ...props } = this.props;
  render() (
    return (
      <div style={{backgroundColor: "blue"}}>
        <input ref={innerRef} {...props} />
      </div>
    )
  )
}

const BeautifulInputForwardingRef = React.forwardRef((props, ref) => (
  <BeautifulInput {...props} innerRef={ref}/>
));

const App = () => (
  <BeautifulInputForwardingRef ref={ref => ref && ref.focus()} />
)

Ref bir sınıfa iletmek için farklı bir prop adı kullanmanız gerekir. innerRefyaygın olarak birçok kütüphanede kullanılmaktadır.


Kodunuzda beautifulInputElementbir React Öğesinden ziyade bir işlev var, şöyle olmalıconst beautifulInputElement = <BeautifulInputForwardingRef ref={ref => ref && ref.focus()} />
Olivier Boissé

8

Temel olarak, bu yalnızca bir HOC işlevidir. Sınıfla birlikte kullanmak istiyorsanız, bunu kendiniz yapabilir ve normal sahne donanımı kullanabilirsiniz.

class TextInput extends React.Component {
    render() {
        <input ref={this.props.forwardRef} />
    }
}

const ref = React.createRef();
<TextInput forwardRef={ref} />

Bu kalıp, örneğin içinde kullanılır styled-componentsve innerReforada çağrılır .


3
Farklı adlandırılmış bir pervane benzeri kullanmak innerRef, noktayı tamamen kaçırmaktır. Amaç tam şeffaflık: <FancyButton>Bir normal DOM öğesi gibi davranabilmeliyim, ancak stilize bileşen yaklaşımını kullanarak, bu bileşenin refs için sadece yerine keyfi olarak adlandırılmış bir destek kullandığını hatırlamam gerekiyor ref.
user128216

2
Her durumda, stilize bileşenler , referansı kullanarak çocuğa geçme lehine desteği bırakmayıinnerRef amaçlamaktadır React.forwardRef, bu da OP'nin başarmaya çalıştığı şeydir.
user128216

5

Bu, isterseniz daha yüksek dereceli bir bileşenle gerçekleştirilebilir:

import React, { forwardRef } from 'react'

const withForwardedRef = Comp => {
  const handle = (props, ref) =>
    <Comp {...props} forwardedRef={ref} />

  const name = Comp.displayName || Comp.name
  handle.displayName = `withForwardedRef(${name})`

  return forwardRef(handle)
}

export default withForwardedRef

Ve sonra bileşen dosyanızda:

class Boop extends React.Component {
  render() {
    const { forwardedRef } = this.props

    return (
      <div ref={forwardedRef} />
    )
  }
}

export default withForwardedRef(Boop)

Çalışmayı önceden testlerle yaptım ve bunun için bir paket yayınladım react-with-forwarded-ref: https://www.npmjs.com/package/react-with-forwarded-ref


3

Bunu birçok farklı bileşende yeniden kullanmanız gerektiğinde, bu yeteneği aşağıdaki gibi bir şeye aktarabilirsiniz: withForwardingRef

const withForwardingRef = <Props extends {[_: string]: any}>(BaseComponent: React.ReactType<Props>) =>
    React.forwardRef((props, ref) => <BaseComponent {...props} forwardedRef={ref} />);

export default withForwardingRef;

kullanım:

const Comp = ({forwardedRef}) => (
 <input ref={forwardedRef} />
)
const EnhanceComponent = withForwardingRef<Props>(Comp);  // Now Comp has a prop called forwardedRef
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.