Panggil metode anak dari orang tua

475

Saya punya dua komponen.

  1. Komponen induk
  2. Komponen anak

Saya mencoba memanggil metode anak dari Orang Tua, saya mencoba cara ini tetapi tidak mendapatkan hasil

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

Apakah ada cara untuk memanggil metode anak dari orang tua?

Catatan: Komponen Anak dan Orang Tua ada dalam dua file berbeda

N8FURY
sumber
Meskipun saya sangat terlambat dalam hal ini, saya juga belajar Bereaksi jadi saya ingin tahu tentang kasus di mana orang tua perlu memanggil metode anak. Tolong jelaskan.
Akshay Raut
Adakah yang tahu cara melakukannya dari fungsi panah? stackoverflow.com/questions/60015693/…
Thomas Segato
@AkshayRaut IMO kasus penggunaan yang baik: formulir tujuan umum dengan fungsi reset dan submit, yang nantinya akan mengembalikan nilai formulir.
Julian K

Jawaban:

702

Pertama, izinkan saya menyatakan bahwa ini umumnya bukan cara untuk melakukan hal-hal di Bereaksi tanah. Biasanya yang ingin Anda lakukan adalah memberikan fungsi kepada anak-anak dalam alat peraga, dan meneruskan pemberitahuan dari anak-anak di acara (atau lebih baik lagi:) dispatch.

Tetapi jika Anda harus mengekspos metode imperatif pada komponen anak, Anda dapat menggunakan referensi . Ingat ini adalah jalan keluar dan biasanya menunjukkan desain yang lebih baik tersedia.

Sebelumnya, referensi hanya didukung untuk komponen berbasis Kelas. Dengan munculnya React Hooks , itu tidak lagi terjadi

Menggunakan Pengait dan Komponen Fungsi ( >= [email protected])

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>

Dokumentasi untuk useImperativeHandle()adalah di sini :

useImperativeHandlemengkustomisasi nilai instance yang diekspos ke komponen induk saat menggunakan ref.

Menggunakan Komponen Kelas ( >= [email protected])

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>

API Warisan ( <= [email protected])

Untuk tujuan historis, inilah gaya berbasis panggilan balik yang akan Anda gunakan dengan React versi sebelum 16.3:

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>

rossipedia
sumber
23
Saya lelah, tetapi berakhir dengan kesalahan ini "_this2.refs.child.getAlert bukan fungsi"
N8FURY
22
Itu karena connectmengembalikan komponen orde tinggi yang membungkus instance asli Anda. Anda harus memanggil getWrappedInstance()komponen yang terhubung terlebih dahulu untuk mendapatkan komponen asli Anda. Kemudian Anda dapat memanggil metode instan untuk itu.
rossipedia
16
Ini sebenarnya bukan pola yang baik. Belum lagi string ref tidak disukai. Lebih baik untuk memasukkan alat peraga ke dalam komponen anak dan kemudian memiliki klik tombol di induknya mengubah keadaan orangtua, dan meneruskan item keadaan ke dalam anak yang akan memicu anak componentWillReceiveProps, dan menggunakannya sebagai pemicu.
ffxsam
8
Tidak, ini biasanya bukan pola terbaik, ini lebih merupakan jalan keluar darurat saat Anda membutuhkannya, dan harus digunakan hanya dalam keadaan darurat. Juga, jawaban ini ditulis ketika ref string masih ada, dan Anda benar bahwa mereka bukan cara yang "benar" dalam melakukan sesuatu hari ini.
rossipedia
35
Jika praktik terbaik adalah membuat labirin logika untuk melakukan sesuatu yang sederhana seperti memanggil metode komponen anak - maka saya tidak setuju dengan praktik terbaik.
aaaaaa
150

Anda dapat menggunakan pola lain di sini:

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

Apa yang dilakukannya adalah mengatur metode induk clickChildketika anak di-mount. Dengan cara ini ketika Anda mengklik tombol pada orang tua itu akan memanggil panggilan clickChildmana yang anak getAlert.

Ini juga berfungsi jika anak Anda dibungkus dengan connect()sehingga Anda tidak perlu getWrappedInstance()meretas.

Catatan Anda tidak dapat menggunakan onClick={this.clickChild}pada orang tua karena ketika orang tua diberikan anak tidak dipasang sehingga this.clickChildbelum ditugaskan. Penggunaannya onClick={() => this.clickChild()}baik-baik saja karena ketika Anda mengklik tombol this.clickChildsudah harus ditugaskan.

brickingup
sumber
5
Saya mengerti _this2.clickChild is not a functionmengapa?
tatsu
1
Nevermind ini bekerja untuk saya: github.com/kriasoft/react-starter-kit/issues/…
tatsu
5
tidak ada yang berhasil. hanya jawaban ini yang berfungsi: github.com/kriasoft/react-starter-kit/issues/…
tatsu
2
Ini adalah teknik yang menarik. Itu cukup bersih dan tampaknya tidak melanggar aturan apa pun. Tapi saya pikir jawaban Anda akan lebih lengkap (dan memenuhi harapan) jika Anda menambahkan ikatan. Saya sangat menyukai jawabannya sehingga saya mempostingnya pada masalah Github terkait ini .
joeytwiddle
8
Ini harus menjadi jawaban yang diterima
Jesus Gomez
28

https://facebook.github.io/react/tips/expose-component-functions.html untuk jawaban lebih lanjut ada di sini Metode panggilan pada komponen React children

Dengan melihat referensi komponen "alasan", Anda memecahkan enkapsulasi dan membuatnya tidak mungkin untuk memperbaiki komponen itu tanpa memeriksa dengan cermat semua tempat yang digunakan. Karena itu, kami sangat menyarankan memperlakukan ref sebagai komponen pribadi, seperti halnya negara.

Secara umum, data harus diturunkan pohon melalui alat peraga. Ada beberapa pengecualian untuk ini (seperti memanggil .focus () atau memicu animasi satu kali yang tidak benar-benar "mengubah" keadaan) tetapi setiap kali Anda mengekspos metode yang disebut "set", alat peraga biasanya pilihan yang lebih baik. Cobalah membuatnya sehingga komponen input dalam khawatir tentang ukuran dan penampilannya sehingga tidak ada leluhurnya yang melakukannya.

Mike Tronic
sumber
5
Inilah sumber jawaban ini: mendiskusikan.reactjs.org/t/… . Tidak ada masalah dengan mengutip orang lain, tetapi setidaknya memasukkan beberapa referensi.
Jodo
1
Bagaimana tepatnya ini memecah enkapsulasi lebih dari alat peraga?
Timmmm
17

Metode alternatif dengan useEffect:

Induk:

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

Anak-anak:

useEffect(() => {
    refresh(); //children function of interest
  }, [props.refresh]);
tonymayoral
sumber
2
Ini harus mendapatkan lebih banyak suara
Ali Al Amine
Ps. Jika keinginan Anda hanya untuk merender ulang formulir (misalnya, untuk mengatur ulang bidang input) maka Anda bahkan tidak perlu menyertakan useEffect, Anda bisa membuat prop dikirim ke perubahan komponen
Matt Fletcher
8

Kita bisa menggunakan referensi dengan cara lain seperti-

Kami akan membuat elemen Induk, itu akan membuat <Child/>komponen. Seperti yang Anda lihat, komponen yang akan di-render, Anda perlu menambahkan atribut ref dan memberikan nama untuknya.
Kemudian, triggerChildAlertfungsi, yang terletak di kelas induk akan mengakses properti referensi konteks ini (ketika triggerChildAlertfungsi dipicu akan mengakses referensi anak dan itu akan memiliki semua fungsi elemen anak).

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

Sekarang, komponen anak, seperti yang dirancang secara teoritis sebelumnya, akan terlihat seperti:

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

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

Berikut adalah kode sumber -
Harapan akan membantu Anda!

S.Yadav
sumber
4

Jika Anda melakukan ini hanya karena Anda ingin Anak memberikan sifat yang dapat digunakan kembali kepada orang tuanya, maka Anda dapat mempertimbangkan melakukan itu menggunakan render-props sebagai gantinya.

Teknik itu sebenarnya membalikkan struktur. The Childsekarang membungkus orang tua, jadi saya telah berganti nama ke AlertTraitbawah. Saya menjaga nama Parentuntuk kesinambungan, meskipun sekarang ini bukan orang tua.

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

Dalam hal ini, AlertTrait menyediakan satu atau beberapa sifat yang dilewatkan sebagai renderComponentpenyangga ke komponen apa pun yang diberikan pada penyangga.

Orangtua menerima doAlertsebagai alat peraga, dan dapat memanggilnya saat dibutuhkan.

(Untuk lebih jelasnya, saya menyebut prop renderComponentdalam contoh di atas. Tetapi dalam React docs yang ditautkan di atas, mereka menyebutnya begitu render.)

Komponen Trait dapat membuat hal-hal di sekitar Induk, dalam fungsi rendernya, tetapi tidak membuat apa pun di dalam induk. Sebenarnya itu bisa membuat hal-hal di dalam Induk, jika melewati prop lain (misrenderChild ) kepada orangtua, yang kemudian dapat digunakan orangtua selama metode rendernya.

Ini agak berbeda dari apa yang diminta OP, tetapi beberapa orang mungkin berakhir di sini (seperti yang kita lakukan) karena mereka ingin membuat sifat yang dapat digunakan kembali, dan berpikir bahwa komponen anak adalah cara yang baik untuk melakukan itu.

joeytwiddle
sumber
Ada daftar pola yang berguna untuk membuat sifat-sifat yang dapat digunakan kembali di sini: reactjs.org/blog/2016/07/13/…
joeytwiddle
Bagaimana jika Anda memiliki N stopwatch dan satu tombol untuk memulai kembali semuanya. Bagaimana membuat alat peraga berguna di sini?
vsync
@vsync Saya tidak yakin metode ini dapat membantu tugas Anda. Tetapi jawaban brickingup mungkin membantu. Perhatikan bahwa mereka mengatur this.clickChild = clicktetapi beberapa stopwatch Anda akan melewati beberapa fungsi, jadi Anda harus menyimpan semuanya:this.watchRestartFuncs[watchId] = restartWatch
joeytwiddle
1

Anda dapat mencapai ini dengan mudah dengan cara ini

Langkah-

  1. Buat variabel boolean dalam status di kelas induk. Perbarui ini saat Anda ingin memanggil suatu fungsi.
  2. Buat variabel prop dan tetapkan variabel boolean.
  3. Dari komponen anak akses variabel itu menggunakan alat peraga dan jalankan metode yang Anda inginkan dengan memiliki kondisi if.

    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>
        );
       }
    }
Kusal Kithmal
sumber
Anda mungkin ingin mem-sandbox ini. Sepertinya Anda akan berakhir dengan loop tak terbatas karena metode anak akan terus berjalan karena status induk disetel ke true.
Isaac Pak
@IsaacPak Ya, itu sebabnya saya meninggalkan komentar di sana, mengatakan Anda harus memperbarui negara sesuai dengan kebutuhan Anda. Maka itu tidak akan berjalan sebagai infinite loop.
Kusal Kithmal
1

Saya menggunakan useEffectkait untuk mengatasi sakit kepala melakukan semua ini jadi sekarang saya meneruskan variabel ke anak seperti ini:

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

Saya tidak puas dengan solusi yang disajikan di sini. Sebenarnya ada solusi yang sangat sederhana yang dapat dilakukan menggunakan Javascript murni tanpa mengandalkan beberapa fungsi Bereaksi selain objek alat peraga dasar - dan itu memberi Anda manfaat berkomunikasi di kedua arah (induk -> anak, anak -> orangtua). Anda perlu meneruskan objek dari komponen induk ke komponen turunan. Objek ini adalah apa yang saya sebut sebagai "referensi dua arah" atau singkatnya biRef. Pada dasarnya, objek berisi referensi ke metode pada induk yang ingin diekspos oleh induk. Dan komponen anak melampirkan metode ke objek yang dapat dipanggil orang tua. Sesuatu seperti ini:

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

Keuntungan lain dari solusi ini adalah Anda dapat menambahkan lebih banyak fungsi di induk dan anak sambil meneruskannya dari induk ke anak dengan hanya menggunakan satu properti.

Peningkatan atas kode di atas adalah untuk tidak menambahkan fungsi induk dan anak secara langsung ke objek biRef melainkan ke sub anggota. Fungsi induk harus ditambahkan ke anggota yang disebut "induk" sedangkan fungsi anak harus ditambahkan ke anggota yang disebut "anak".

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

Dengan menempatkan fungsi orangtua dan anak ke dalam anggota yang terpisah dari objek biRef, Anda akan memiliki pemisahan yang bersih antara keduanya dan dengan mudah melihat mana yang milik orangtua atau anak. Ini juga membantu mencegah komponen anak dari menimpa fungsi orangtua secara tidak sengaja jika fungsi yang sama muncul di keduanya.

Satu hal terakhir adalah bahwa jika Anda perhatikan, komponen induk membuat objek biRef dengan var sedangkan komponen anak mengaksesnya melalui objek props. Mungkin tergoda untuk tidak mendefinisikan objek biRef di induk dan mengaksesnya dari induknya melalui parameter propsnya sendiri (yang mungkin merupakan kasus dalam hierarki elemen UI). Ini berisiko karena anak mungkin berpikir suatu fungsi yang dipanggilnya pada orangtua adalah milik orangtua padahal sebenarnya itu milik kakek-nenek. Tidak ada yang salah dengan ini selama Anda menyadarinya. Kecuali Anda memiliki alasan untuk mendukung beberapa hierarki di luar hubungan orang tua / anak, yang terbaik adalah membuat biRef di komponen induk Anda.

AndroidDev
sumber
0

Saya pikir cara paling dasar untuk memanggil metode adalah dengan menetapkan permintaan pada komponen anak. Kemudian segera setelah anak menangani permintaan, ia memanggil metode panggilan balik untuk mereset permintaan.

Mekanisme reset diperlukan untuk dapat mengirim permintaan yang sama beberapa kali setelah satu sama lain.

Dalam komponen induk

Dalam metode render dari induk:

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

Orang tua membutuhkan 2 metode, untuk berkomunikasi dengan anaknya dalam 2 arah.

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

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

Dalam komponen anak

Anak itu memperbarui keadaan internalnya, menyalin permintaan dari alat peraga.

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

Lalu akhirnya ia menangani permintaan, dan mengirimkan reset ke induk:

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

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

Cara lain untuk memicu fungsi anak dari orang tua adalah dengan memanfaatkan componentDidUpdatefungsi dalam Komponen anak. Saya melewati prop triggerChildFuncdari Parent to Child, yang awalnya adalah null. Nilai berubah menjadi fungsi ketika tombol diklik dan Anak melihat bahwa perubahan componentDidUpdatedan memanggil fungsi internalnya sendiri.

Karena prop triggerChildFuncberubah ke fungsi, kami juga menerima panggilan balik ke Induk. Jika Induk tidak perlu tahu kapan fungsi dipanggil nilai triggerChildFuncmisalnya bisa berubah dari nullmenjadi true.

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

Calsal
sumber
0

Di sini, demo saya: https://stackblitz.com/edit/react-dgz1ee?file=styles.css

Saya menggunakan useEffectuntuk memanggil metode komponen anak-anak. Saya sudah mencoba Proxy and Setter_Gettertetapi useEffecttampaknya jauh lebih mudah untuk memanggil metode anak dari orang tua. Untuk menggunakannya Proxy and Setter_Gettersepertinya ada beberapa kehalusan untuk diatasi terlebih dahulu, karena elemen yang pertama kali diberikan adalah elemen objectLike melalui ref.current return => <div/>spesifisitas. Mengenai useEffect, Anda juga dapat memanfaatkan pendekatan ini untuk mengatur keadaan orang tua tergantung pada apa yang ingin Anda lakukan dengan anak-anak.

Di tautan demo yang saya berikan, Anda akan menemukan kode ReactJS saya lengkap dengan konsep saya di dalam sehingga Anda dapat menghargai alur kerja solusi saya.

Di sini saya memberi Anda hanya potongan kode ReactJS saya yang relevan. :

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>
       )
}
Wanita web
sumber
0

Kami senang dengan kait khusus yang kami sebut useCounterKey. Itu hanya membuat counterKey, atau kunci yang dihitung dari nol. Fungsi yang dikembalikan mengembalikan kunci (mis. Kenaikan). (Saya percaya ini adalah cara paling idiomatis dalam Bereaksi untuk mereset komponen - cukup tekan tombol.)

Namun kait ini juga berfungsi dalam situasi apa pun di mana Anda ingin mengirim pesan satu kali kepada klien untuk melakukan sesuatu. Misalnya kita menggunakannya untuk memfokuskan kontrol pada anak pada acara induk tertentu - itu hanya fokus otomatis kapan saja kunci diperbarui. (Jika lebih banyak alat peraga diperlukan, mereka dapat diatur sebelum mengatur ulang kunci sehingga tersedia saat acara terjadi.)

Metode ini memiliki sedikit kurva belajar b / c tidak semudah penanganan kejadian biasa, tetapi tampaknya cara yang paling idiomatis untuk menangani ini dalam Bereaksi yang kami temukan (karena kunci sudah berfungsi dengan cara ini). Def terbuka untuk umpan balik tentang metode ini tetapi itu bekerja dengan baik!

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

Penggunaan sampel:

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

  // ...
}

(Kredit untuk Kent Dodds untuk konsep kontraKey .)

Freewalker
sumber
-1

Ini bugnya? yang harus diwaspadai: Saya setuju dengan solusi rossipedia menggunakan forwardRef, useRef, useImperativeHandle

Ada beberapa informasi yang salah di internet yang mengatakan bahwa referensi hanya dapat dibuat dari komponen React Class, tetapi Anda memang dapat menggunakan Komponen Fungsi jika Anda menggunakan kait yang disebutkan di atas. Catatan, kait hanya berfungsi untuk saya setelah saya mengubah file untuk tidak menggunakan withRouter () saat mengekspor komponen. Yaitu perubahan dari

export default withRouter(TableConfig);

untuk menjadi

export default TableConfig;

Di belakang withRouter () tidak diperlukan untuk komponen seperti itu, tapi biasanya tidak ada salahnya masuk. Kasus penggunaan saya adalah saya membuat komponen untuk membuat Tabel untuk menangani tampilan dan pengeditan nilai konfigurasi, dan saya ingin dapat memberi tahu komponen Child ini untuk mereset nilai-nilai keadaannya setiap kali tombol Reset formulir Induk ditekan. UseRef () tidak akan mendapatkan ref atau ref.current dengan benar (terus menjadi nol) sampai saya dihapus denganRouter () dari file yang mengandung komponen anak saya TableConfig

DeltaPng
sumber