Üst öğeden alt yöntemi çağır


474

İki bileşenim var.

  1. Ana bileşen
  2. Alt bileşen

Ebeveynten çocuğun yöntemini çağırmaya çalışıyordum, bu şekilde denedim ama sonuç alamadım

class Parent extends Component {
  render() {
    return (
      <Child>
        <button onClick={Child.getAlert()}>Click</button>
      </Child>
      );
    }
  }

class Child extends Component {
  getAlert() {
    alert('clicked');
  }

  render() {
    return (
      <h1 ref="hello">Hello</h1>
    );
  }
}

Ebeveynten çocuğun yöntemini çağırmanın bir yolu var mı?

Not: Alt ve Üst bileşenler iki farklı dosyada bulunur


Buna çok geç kalmama rağmen, React'i de öğreniyorum, bu yüzden bir ebeveynin çocuk yöntemini çağırması gereken durum hakkında bilmek istiyorum. Lütfen açıklar mısınız?
Akshay Raut

Herkes bunu ok işlevlerinden nasıl biliyor? stackoverflow.com/questions/60015693/…
Thomas Segato

@AkshayRaut IMO iyi bir kullanım senaryosu: sıfırlama ve gönderme işlevlerine sahip genel amaçlı bir form, daha sonra form değerlerini döndürür.
Julian K

Yanıtlar:


702

Öncelikle, bunun React ülkesindeki şeyler hakkında genel olarak bir yol olmadığını ifade edeyim . Genellikle yapmak istediğiniz şey, işlevselliği çocuklarda işlevselliğe bırakmak ve etkinliklerde çocuklardan gelen bildirimleri (veya daha iyisi:) iletmektir dispatch.

Ancak , bir alt bileşen üzerinde zorunlu bir yöntem göstermeniz gerekiyorsa , refs kullanabilirsiniz . Bunun bir kaçış kapağı olduğunu ve genellikle daha iyi bir tasarımın mevcut olduğunu gösterir.

Önceden referanslar yalnızca Sınıf tabanlı bileşenler için destekleniyordu. React Hooks'un ortaya çıkışı ile artık durum böyle değil

Kancaları ve İşlev Bileşenlerini Kullanma ( >= react@16.8)

const { forwardRef, useRef, useImperativeHandle } = React;

// We need to wrap component in `forwardRef` in order to gain
// access to the ref object that is assigned using the `ref` prop.
// This ref is passed as the second parameter to the function component.
const Child = forwardRef((props, ref) => {

  // The component instance will be extended
  // with whatever you return from the callback passed
  // as the second argument
  useImperativeHandle(ref, () => ({

    getAlert() {
      alert("getAlert from Child");
    }

  }));

  return <h1>Hi</h1>;
});

const Parent = () => {
  // In order to gain access to the child component instance,
  // you need to assign it to a `ref`, so we call `useRef()` to get one
  const childRef = useRef();

  return (
    <div>
      <Child ref={childRef} />
      <button onClick={() => childRef.current.getAlert()}>Click</button>
    </div>
  );
};

ReactDOM.render(
  <Parent />,
  document.getElementById('root')
);
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>

<div id="root"></div>

İçin Belgeler useImperativeHandle()olduğunu burada :

useImperativeHandlekullanırken üst bileşenlere maruz kalan örnek değerini özelleştirir ref.

Sınıf Bileşenlerini Kullanma ( >= react@16.4)

const { Component } = React;

class Parent extends Component {
  constructor(props) {
    super(props);
    this.child = React.createRef();
  }

  onClick = () => {
    this.child.current.getAlert();
  };

  render() {
    return (
      <div>
        <Child ref={this.child} />
        <button onClick={this.onClick}>Click</button>
      </div>
    );
  }
}

class Child extends Component {
  getAlert() {
    alert('getAlert from Child');
  }

  render() {
    return <h1>Hello</h1>;
  }
}

ReactDOM.render(<Parent />, document.getElementById('root'));
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
<div id="root"></div>

Eski API ( <= react@16.3)

Geçmişteki amaçlar için, 16.3'ten önceki React sürümleriyle kullanacağınız geri arama tabanlı stil:

const { Component } = React;
const { render } = ReactDOM;

class Parent extends Component {
  render() {
    return (
      <div>
        <Child ref={instance => { this.child = instance; }} />
        <button onClick={() => { this.child.getAlert(); }}>Click</button>
      </div>
    );
  }
}

class Child extends Component {
  getAlert() {
    alert('clicked');
  }

  render() {
    return (
      <h1>Hello</h1>
    );
  }
}


render(
  <Parent />,
  document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="app"></div>


23
Yorgunum ama bu hatayla sonuçlandım "_this2.refs.child.getAlert bir işlev değil"
N8FURY

22
Çünkü connectorijinal örneğinizi saran daha üst düzey bir bileşen döndürür. getWrappedInstance()Orijinal bileşeninizi almak için önce bağlı bileşeni aramanız gerekir . Sonra bu konuda örnek yöntemleri çağırabilirsiniz.
rossipedia

16
Bu gerçekten iyi bir model değil. Bahsetmiyorum bile dize refs kaşlarını çattı. Yardımcıları alt bileşene geçirmek ve daha sonra üst öğede bir düğmeyi tıklatmak üst öğenin durumunu değiştirmek ve alt öğeyi çocuğun tetikleyeceği ve tetikleyici olarak kullanacak bir durum öğesini iletmek daha iyidir componentWillReceiveProps.
ffxsam

7
Hayır, genellikle en iyi desen değildir, ihtiyacınız olduğunda bir kaçış kapağıdır ve sadece acil durumlarda kullanılmalıdır. Ayrıca, bu cevap dizgi referansları hala ortadayken yazılmıştır ve bu günlerde bir şeyler yapmanın "doğru" yolu olmadığından emin olabilirsiniz.
rossipedia

35
En iyi yöntem, bir alt bileşenin yöntemini çağırmak kadar basit bir şey yapmak için bir mantık labirenti oluşturmaksa - o zaman en iyi uygulamaya katılmıyorum.
aaaaaa

149

Burada başka bir desen kullanabilirsiniz:

class Parent extends Component {
 render() {
  return (
    <div>
      <Child setClick={click => this.clickChild = click}/>
      <button onClick={() => this.clickChild()}>Click</button>
    </div>
  );
 }
}

class Child extends Component {
 constructor(props) {
    super(props);
    this.getAlert = this.getAlert.bind(this);
 }
 componentDidMount() {
    this.props.setClick(this.getAlert);
 }
 getAlert() {
    alert('clicked');
 }
 render() {
  return (
    <h1 ref="hello">Hello</h1>
  );
 }
}

clickChildÇocuk monte edildiğinde ebeveynin yöntemini ayarlamaktır . Bu şekilde üst öğedeki düğmeyi tıklattığınızda, clickChildçocuğun çağrısını çağıran çağrı yapılır getAlert.

Bu, çocuğunuzla sarılmışsa da işe yarar, connect()bu yüzden getWrappedInstance()kesmek gerekmez .

onClick={this.clickChild}Üst öğe oluşturulamadığından alt this.clickChildöğe henüz atanmadığı için üst öğede kullanamayacağınızı unutmayın . Kullanmak onClick={() => this.clickChild()}iyidir çünkü düğmeyi tıkladığınızda this.clickChildatanmış olmalıdır.


5
_this2.clickChild is not a functionNeden anladım ?
tatsu

1
nevermind bu benim için çalıştı: github.com/kriasoft/react-starter-kit/issues/…
tatsu

5
ikisi de işe yaramadı. sadece bu cevap çalıştı: github.com/kriasoft/react-starter-kit/issues/…
tatsu

2
Bu ilginç bir teknik. Oldukça temiz ve herhangi bir kuralı ihlal ediyor gibi görünmüyor. Ancak, bir bağlama eklediyseniz cevabınızın daha eksiksiz olacağını (ve beklentileri karşılayacağını) düşünüyorum. Cevabı bu ilgili Github sorununa gönderdim .
joeytwiddle

7
Bu kabul edilen cevap olmalı
Jesus Gomez

27

https://facebook.github.io/react/tips/expose-component-functions.html Daha fazla yanıt için buraya bakın Çocuklara tepki verme bileşenleri ile ilgili yöntemleri arayın

"Sebep" bileşeninin referanslarına bakarak, kapsüllemeyi kırarsınız ve kullanıldığı tüm yerleri dikkatlice incelemeden bu bileşeni yeniden düzenlemeyi imkansız hale getirirsiniz. Bu nedenle, ref'lerin devlete çok benzeyen bir bileşene özel olarak davranılmasını önemle tavsiye ederiz.

Genel olarak, veriler sahne boyunca ağaçtan geçirilmelidir. Bunun birkaç istisnası vardır (örneğin .focus () çağırma veya durumu "gerçekten" değiştirmeyen bir kerelik bir animasyonu tetikleme), ancak "set" adı verilen bir yöntemi ortaya koyduğunuzda sahne genellikle daha iyi bir seçim. İç girdi bileşeni, atalarının hiçbirinin yapmaması için boyutu ve görünümü hakkında endişelenecek şekilde yapmaya çalışın.


5
İşte bu cevabın kaynağı: tartış.reactjs.org/t/… . Başkalarına atıfta bulunmakla ilgili bir sorun yok, ama en azından bazı referansları belirtin.
Jodo

1
Bu, kapsüllemeyi tam olarak aksesuarlardan daha fazla nasıl kırıyor?
Timmmm

15

UseEffect ile alternatif yöntem:

Veli:

const [refresh, doRefresh] = useState(0);
<Button onClick={()=>doRefresh(refresh+1)} />
<Children refresh={refresh} />

Çocuk:

useEffect(() => {
    refresh(); //children function of interest
  }, [props.refresh]);

2
Bu daha fazla oy almalı
Ali Al Amine

Ps. Arzunuz sadece formu yeniden oluşturmaksa (örneğin, giriş alanlarını sıfırlamak için) useEffect'i eklemenize bile gerek yoktur, sadece propın bileşen değişikliğine gönderilmesini sağlayabilirsiniz
Matt Fletcher

8

Ref'leri başka bir şekilde kullanabiliriz-

Bir Üst öğe oluşturacağız, bir <Child/>bileşen oluşturacak . Gördüğünüz gibi, oluşturulacak bileşen, ref niteliğini eklemeniz ve bunun için bir ad vermeniz gerekir.
Daha sonra, triggerChildAlertüst sınıfta bulunan işlev bu bağlamın refs özelliğine erişecektir ( triggerChildAlertişlev tetiklendiğinde alt referansa erişecek ve alt öğenin tüm işlevlerine sahip olacaktır).

class Parent extends React.Component {
    triggerChildAlert(){
        this.refs.child.callChildMethod();
        // to get child parent returned  value-
        // this.value = this.refs.child.callChildMethod();
        // alert('Returned value- '+this.value);
    }

    render() {
        return (
            <div>
                {/* Note that you need to give a value to the ref parameter, in this case child*/}
                <Child ref="child" />
                <button onClick={this.triggerChildAlert}>Click</button>
            </div>
        );
    }
}  

Şimdi, daha önce teorik olarak tasarlandığı gibi alt bileşen şöyle görünecektir:

class Child extends React.Component {
    callChildMethod() {
        alert('Hello World');
        // to return some value
        // return this.state.someValue;
    }

    render() {
        return (
            <h1>Hello</h1>
        );
    }
}

İşte kaynak kodu-
Umut size yardımcı olacaktır!


1
Dize başvuruları kullanımdan kaldırıldı. reaktjs.org/docs/refs-and-the-dom.html#legacy-api-string-refs
Cory McAboy

4

Bunu sadece Çocuğun ebeveynlerine yeniden kullanılabilir bir özellik sağlamasını istediğiniz için yapıyorsanız, bunu bunun yerine render-props kullanarak yapmayı düşünebilirsiniz .

Bu teknik aslında yapıyı tersine çevirir. ChildBen bunu yeniden adlandırmış şimdi, ebeveyn sarar AlertTraitaltında. ParentSüreklilik için adı korudum , ancak şimdi gerçekten bir ebeveyn olmasa da.

// Use it like this:

  <AlertTrait renderComponent={Parent}/>


class AlertTrait extends Component {
  // You may need to bind this function, if it is stateful
  doAlert() {
    alert('clicked');
  }
  render() {
    return this.props.renderComponent(this.doAlert);
  }
}

class Parent extends Component {
  render() {
    return (
      <button onClick={this.props.doAlert}>Click</button>
    );
  }
}

Bu durumda, AlertTrait, renderComponentpervanesinde verilen herhangi bir bileşene destek olarak ilettiği bir veya daha fazla özellik sağlar .

Ebeveyn doAlertdestek olarak alır ve gerektiğinde arayabilir.

(Açıklık renderComponentiçin yukarıdaki örnekte pervane adını verdim . Ancak yukarıda bağlanan React belgelerinde sadece çağırıyorlar render.)

Trait bileşeni, oluşturma işlevinde Üst Öğeyi çevreleyen öğeleri oluşturabilir, ancak üst öğenin içinde hiçbir şey oluşturmaz. Aslında, üst öğeye başka bir destek (örn. renderChild) Geçerse, üst öğenin oluşturma yöntemi sırasında kullanabileceği Üst Öğenin içinde bir şeyler oluşturabilir.

Bu OP'nin istediğinden biraz farklıdır, ancak bazı insanlar burada (bizim yaptığımız gibi) sonuçlanabilir, çünkü tekrar kullanılabilir bir özellik yaratmak istediler ve bir çocuk bileşeninin bunu yapmanın iyi bir yolu olduğunu düşündüler.


Burada yeniden kullanılabilir özellikler oluşturmak için kullanışlı bir desen listesi vardır: reaktjs.org/blog/2016/07/13/…
joeytwiddle

N kronometreniz ve hepsini yeniden başlatmak için bir düğmeniz varsa ne olur. Buradaki destekleri nasıl kullanışlı hale getirir?
vsync

@vsync Bu yöntemin görevinize yardımcı olabileceğinden emin değilim. Ancak brickingup'ın cevabı yardımcı olabilir. Ayarladıklarını this.clickChild = clickancak çoklu kronometrelerinizin birden fazla işlevi geçeceğini unutmayın, bu yüzden hepsini saklamanız gerekir:this.watchRestartFuncs[watchId] = restartWatch
joeytwiddle

1

Bunu kolayca bu şekilde başarabilirsiniz

adımları-

  1. Üst sınıftaki durumda bir boolean değişkeni oluşturun. Bir işlevi çağırmak istediğinizde bunu güncelleyin.
  2. Bir prop değişkeni oluşturun ve boolean değişkenini atayın.
  3. Alt bileşenden, pro kullanarak pro değişkenine erişin ve bir if koşuluyla istediğiniz yöntemi çalıştırın.

    class Child extends Component {
       Method=()=>{
       --Your method body--
       }
       render() {
         return (
        //check whether the variable has been updated or not
          if(this.props.updateMethod){
            this.Method();
          }
         )
       }
    }
    
    class Parent extends Component {
    
    constructor(){
      this.state={
       callMethod:false
      }
    
    }
    render() {
       return (
    
         //update state according to your requirement
         this.setState({
            callMethod:true
         }}
         <Child updateMethod={this.state.callMethod}></Child>
        );
       }
    }

Bunu korumalı alan yapmak isteyebilirsiniz. Ebeveyn durumu true olarak ayarlandığından, child yöntemi sürekli olarak çalışacağından sonsuz bir döngü elde edeceğiniz anlaşılıyor.
Isaac Pak

@IsaacPak Evet, bu yüzden devleti ihtiyacınıza göre güncellemeniz gerektiğini söyleyerek bir yorum bıraktım. O zaman sonsuz bir döngü olarak çalışmaz.
Kusal Kithmal

1

useEffectTüm bunları yapmanın baş ağrısının üstesinden gelmek için kanca kullanıyorum , bu yüzden şimdi çocuğa böyle bir değişkeni geçiyorum:

<ParentComponent>
 <ChildComponent arbitrary={value} />
</ParentComponent>
useEffect(() => callTheFunctionToBeCalled(value) , [value]);

1

Burada sunulan çözümlerin hiçbirinden memnun kalmadım. Aslında, temel sahne nesnesi dışındaki bazı React işlevlerine dayanmadan saf Javascript kullanılarak yapılabilecek çok basit bir çözüm vardır - ve size her iki yönde (ebeveyn -> çocuk, çocuk -> ebeveyn) iletişim kurma avantajı sağlar. Bir nesneyi üst bileşenden alt bileşene geçirmeniz gerekir. Bu nesne kısaca "iki yönlü referans" veya biRef olarak adlandırdığım şeydir. Temel olarak, nesne üst öğede üst öğenin göstermek istediği yöntemlere bir başvuru içerir. Alt bileşen, üst öğenin çağırabileceği nesneye yöntemler ekler. Bunun gibi bir şey:

// Parent component.
function MyParentComponent(props) {

   function someParentFunction() {
      // The child component can call this function.
   }

   function onButtonClick() {
       // Call the function inside the child component.
       biRef.someChildFunction();
   }

   // Add all the functions here that the child can call.
   var biRef = {
      someParentFunction: someParentFunction
   }

   return <div>
       <MyChildComponent biRef={biRef} />
       <Button onClick={onButtonClick} />
   </div>;
}


// Child component
function MyChildComponent(props) {

   function someChildFunction() {
      // The parent component can call this function.
   }


   function onButtonClick() {
      // Call the parent function.
      props.biRef.someParentFunction();
   }

   // Add all the child functions to props.biRef that you want the parent
   // to be able to call.
   props.biRef.someChildFunction = someChildFunction;

   return <div>
       <Button onClick={onButtonClick} />
   </div>;
}

Bu çözümün diğer avantajı, ebeveyn ve çocukta yalnızca tek bir özellik kullanarak ebeveynlerden çocuğa geçirirken çok daha fazla işlev ekleyebilmenizdir.

Yukarıdaki kod üzerinde yapılan bir iyileştirme, üst ve alt işlevleri doğrudan biRef nesnesine değil alt üyelere eklemektir. Üst işlevler "üst" adlı bir üyeye eklenmelidir; alt işlevler ise "alt" adlı bir üyeye eklenmelidir.

// Parent component.
function MyParentComponent(props) {

   function someParentFunction() {
      // The child component can call this function.
   }

   function onButtonClick() {
       // Call the function inside the child component.
       biRef.child.someChildFunction();
   }

   // Add all the functions here that the child can call.
   var biRef = {
      parent: {
          someParentFunction: someParentFunction
      }
   }

   return <div>
       <MyChildComponent biRef={biRef} />
       <Button onClick={onButtonClick} />
   </div>;
}


// Child component
function MyChildComponent(props) {

   function someChildFunction() {
      // The parent component can call this function.
   }


   function onButtonClick() {
      // Call the parent function.
      props.biRef.parent.someParentFunction();
   }

   // Add all the child functions to props.biRef that you want the parent
   // to be able to call.
   props.biRef {
       child: {
            someChildFunction: someChildFunction
       }
   }

   return <div>
       <Button onClick={onButtonClick} />
   </div>;
}

Ebeveyn ve çocuk işlevlerini biRef nesnesinin ayrı üyelerine yerleştirerek, ikisi arasında temiz bir ayrım olur ve hangilerinin ebeveyn veya çocuğa ait olduğunu kolayca görürsünüz. Ayrıca, her ikisinde de aynı işlev görünürse, bir alt bileşenin yanlışlıkla bir üst işlevin üzerine yazmasını önlemeye yardımcı olur.

Son bir şey, not ederseniz, üst bileşenin var ile biRef nesnesini oluşturması, alt bileşenin ise props nesnesi üzerinden erişmesidir. Üst öğedeki biRef nesnesini tanımlamamak ve bu öğeye kendi sahne parametresi (üst öğe öğelerinin hiyerarşisinde geçerli olabilir) aracılığıyla üst öğesinden erişmemek cazip gelebilir. Bu risklidir çünkü çocuk ebeveyn üzerinde çağırdığı bir fonksiyonun aslında bir büyükbaba veya büyükanneye ait olabileceği durumlarda ebeveyne ait olduğunu düşünebilir. Farkında olduğunuz sürece bununla ilgili yanlış bir şey yok. Bir üst / alt ilişkinin ötesinde bir hiyerarşiyi desteklemek için bir nedeniniz olmadıkça, üst bileşeninizde biRef oluşturmak en iyisidir.



0

Yöntemleri çağırmanın en temel yolunun alt bileşen için bir istek ayarlamak olduğunu düşünüyorum. Sonra çocuk isteği işleme koyar koymaz, isteği sıfırlamak için bir geri arama yöntemi çağırır.

Sıfırlama mekanizması, aynı isteği birbiri ardına birden çok kez gönderebilmek için gereklidir.

Üst bileşende

Üst öğenin oluşturma yönteminde:

const { request } = this.state;
return (<Child request={request} onRequestHandled={()->resetRequest()}/>);

Ebeveyn, çocuğuyla 2 yönde iletişim kurmak için 2 yönteme ihtiyaç duyar.

sendRequest() {
  const request = { param: "value" };
  this.setState({ request });
}

resetRequest() {
  const request = null;
  this.setState({ request });
}

Alt bileşende

Çocuk, isteğini desteklerden kopyalayarak dahili durumunu günceller.

constructor(props) {
  super(props);
  const { request } = props;
  this.state = { request };
}

static getDerivedStateFromProps(props, state) {
  const { request } = props;
  if (request !== state.request ) return { request };
  return null;
}

Daha sonra isteği işleme koyar ve sıfırlamayı üst öğeye gönderir:

componentDidMount() {
  const { request } = this.state;
  // todo handle request.

  const { onRequestHandled } = this.props;
  if (onRequestHandled != null) onRequestHandled();
}

0

Ana öğeden alt öğe işlevini tetiklemenin başka bir yolu, componentDidUpdatealt bileşendeki işlevi kullanmaktır . triggerChildFuncBaşlangıçta olan Ana Babadan Çocuğa bir pervane geçiyorum null. Düğme tıklatıldığında değer bir işlev olarak değişir ve Çocuk bu değişikliği değiştirir componentDidUpdateve kendi dahili işlevini çağırır.

Prop triggerChildFuncbir işlevde değiştiğinden, Ebeveyn için bir geri arama da alırız. Fonksiyon değeri çağrıldığında Veli bilmek gerekir yoksa triggerChildFunccould örnek değişim için nulliçin trueyerine.

const { Component } = React;
const { render } = ReactDOM;

class Parent extends Component {
  state = {
    triggerFunc: null
  }

  render() {
    return (
      <div>
        <Child triggerChildFunc={this.state.triggerFunc} />
        <button onClick={() => {
          this.setState({ triggerFunc: () => alert('Callback in parent')})
        }}>Click
        </button>
      </div>
    );
  }
}

class Child extends Component {
  componentDidUpdate(prevProps) {
    if (this.props.triggerChildFunc !== prevProps.triggerChildFunc) {
      this.onParentTrigger();
    }
  }

  onParentTrigger() {
    alert('parent triggered me');

    // Let's call the passed variable from parent if it's a function
    if (this.props.triggerChildFunc && {}.toString.call(this.props.triggerChildFunc) === '[object Function]') {
      this.props.triggerChildFunc();
    }
  }

  render() {
    return (
      <h1>Hello</h1>
    );
  }
}


render(
  <Parent />,
  document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='app'></div>

CodePen: https://codepen.io/calsal/pen/NWPxbJv?editors=1010


0

İşte demom: https://stackblitz.com/edit/react-dgz1ee?file=styles.css

useEffectÇocuk bileşeninin yöntemlerini çağırmak için kullanıyorum . Ben denedim Proxy and Setter_Getterama sor çok useEffectebeveyn bir çocuk yöntemi çağırmak için daha uygun bir yol gibi görünüyor. Kullanmak Proxy and Setter_Getterilk önce üstesinden gelmek için bazı incelikler var gibi görünüyor, çünkü ilk olarak oluşturulan eleman ref.current return => <div/>'ın özgüllüğü yoluyla bir objectLike öğesidir . Bununla ilgili olarak useEffect, çocuklarla ne yapmak istediğinize bağlı olarak ebeveynin durumunu ayarlamak için bu yaklaşımdan yararlanabilirsiniz.

Demo'nun sağladığım bağlantısında, ReactJS kodumu taslaklarımın içinde bulacaksınız, böylece çözümümün iş akışını takdir edebilirsiniz.

Burada size ReactJS snippet'imi sadece ilgili kodla sağlıyorum. :

import React, {
  Component,
  createRef,
  forwardRef,
  useState,
  useEffect
} from "react"; 

{...}

// Child component
// I am defining here a forwardRef's element to get the Child's methods from the parent
// through the ref's element.
let Child = forwardRef((props, ref) => {
  // I am fetching the parent's method here
  // that allows me to connect the parent and the child's components
  let { validateChildren } = props;
  // I am initializing the state of the children
  // good if we can even leverage on the functional children's state
  let initialState = {
    one: "hello world",
    two: () => {
      console.log("I am accessing child method from parent :].");
      return "child method achieve";
    }
  };
  // useState initialization
  const [componentState, setComponentState] = useState(initialState);
  // useEffect will allow me to communicate with the parent
  // through a lifecycle data flow
  useEffect(() => {
    ref.current = { componentState };
    validateChildren(ref.current.componentState.two);
  });

{...}

});

{...}

// Parent component
class App extends Component {
  // initialize the ref inside the constructor element
  constructor(props) {
    super(props);
    this.childRef = createRef();
  }

  // I am implementing a parent's method
  // in child useEffect's method
  validateChildren = childrenMethod => {
    // access children method from parent
    childrenMethod();
    // or signaling children is ready
    console.log("children active");
  };

{...}
render(){
       return (
          {
            // I am referencing the children
            // also I am implementing the parent logic connector's function
            // in the child, here => this.validateChildren's function
          }
          <Child ref={this.childRef} validateChildren={this.validateChildren} />
        </div>
       )
}

0

Özel bir kanca ile mutluyuz useCounterKey. Sadece bir counterKey veya sıfırdan sayan bir anahtar ayarlar. Döndürdüğü işlev tuşu sıfırlar (yani artış). ( React'ın bir bileşeni sıfırlamanın en deyimsel yolu olduğuna inanıyorum - sadece anahtarı çarptı.)

Ancak bu kanca, istemciye bir şey yapmak için bir kerelik mesaj göndermek istediğiniz her durumda da çalışır. Örneğin, bir kontrolü belirli bir ebeveyn olayına odaklamak için kullanırız - anahtar her güncellendiğinde otomatik olarak odaklanır. (Daha fazla sahne gerekirse, anahtar sıfırlanmadan önce etkinlik gerçekleştiğinde kullanılabilir olmaları için ayarlanabilirler.)

Bu yöntemin biraz öğrenme eğrisi vardır b / c, tipik bir olay işleyicisi kadar basit değildir, ancak bulduğumuz React'ta bunu işlemenin en deyimsel yolu gibi görünüyor (çünkü tuşlar zaten bu şekilde çalışıyor). Def bu yöntem hakkında geri bildirim açık ama iyi çalışıyor!

// Main helper hook:
export function useCounterKey() {
  const [key, setKey] = useState(0);
  return [key, () => setKey(prev => prev + 1)] as const;
}

Örnek kullanımlar:

// Sample 1 - normal React, just reset a control by changing Key on demand
function Sample1() {
  const [inputLineCounterKey, resetInputLine] = useCounterKey();

  return <>
    <InputLine key={inputLineCounterKey} />
    <button onClick={() => resetInputLine()} />
  <>;
}

// Second sample - anytime the counterKey is incremented, child calls focus() on the input
function Sample2() {
  const [amountFocusCounterKey, focusAmountInput] = useCounterKey();

  // ... call focusAmountInput in some hook or event handler as needed

  return <WorkoutAmountInput focusCounterKey={amountFocusCounterKey} />
}

function WorkoutAmountInput(props) {
  useEffect(() => {
    if (counterKey > 0) {
      // Don't focus initially
      focusAmount();
    }
  }, [counterKey]);

  // ...
}

( CounterKey konsepti için Kent Dodds'a teşekkür ederiz .)


-1

İşte bir hata mı? dışarı bakmak için: Ben forwardRef, useRef, useImperativeHandle kullanarak rossipedia's çözüm ile aynı fikirde

Ref'lerin yalnızca React Sınıfı bileşenlerinden oluşturulabileceğini söyleyen çevrimiçi bazı yanlış bilgiler var, ancak yukarıda belirtilen kancaları kullanırsanız gerçekten İşlev Bileşenlerini kullanabilirsiniz. Bir not, kancalar sadece bileşeni dışarı aktarırken dosyayı withRouter () ile kullanmak için değiştirdikten sonra benim için çalıştı. Yani bir değişiklik

export default withRouter(TableConfig);

bunun yerine olmak

export default TableConfig;

Sonradan böyle bir bileşen için withRouter () gerekli değildir, ancak genellikle içinde bulunan hiçbir şeye zarar vermez. Kullanım durumum, yapılandırma değerlerinin görüntülenmesi ve düzenlenmesi için bir Tablo oluşturmak üzere bir bileşen oluşturmam, Üst öğenin Sıfırla düğmesine her basıldığında bu Alt bileşene durum değerlerini sıfırlamasını söyleyebilmek istedim. UseRef (), alt bileşenimi TableConfig içeren dosyadan (

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.