Bagaimana cara mengakses metode komponen dari "luar" di ReactJS?

183

Mengapa saya tidak bisa mengakses metode komponen dari "luar" di ReactJS? Mengapa itu tidak mungkin dan apakah ada cara untuk menyelesaikannya?

Pertimbangkan kodenya:

var Parent = React.createClass({
    render: function() {
        var child = <Child />;
        return (
            <div>
                {child.someMethod()} // expect "bar", got a "not a function" error.
            </div>
        );
    }
});

var Child = React.createClass({
    render: function() {
        return (
            <div>
                foo
            </div>
        );
    },
    someMethod: function() {
        return 'bar';
    }
});

React.renderComponent(<Parent />, document.body);
pengguna1518183
sumber
Mungkin Anda butuh Pubsub?
slideshowp2

Jawaban:

203

Bereaksi menyediakan antarmuka untuk apa yang Anda coba lakukan melalui refatribut . Tetapkan komponen a ref, dan currentatributnya akan menjadi komponen khusus Anda:

class Parent extends React.Class {
    constructor(props) {
        this._child = React.createRef();
    }

    componentDidMount() {
        console.log(this._child.current.someMethod()); // Prints 'bar'
    }

    render() {
        return (
            <div>
                <Child ref={this._child} />
            </div>
        );
    }
}

Catatan : Ini hanya akan berfungsi jika komponen anak dinyatakan sebagai kelas, sesuai dokumentasi yang ditemukan di sini: https://facebook.github.io/react/docs/refs-and-the-dom.html#adding-a- ref-to-a-class-komponen

Pembaruan 2019-04-01: Contoh yang diubah untuk menggunakan kelas dan createRefper dokumen Bereaksi terbaru.

Update 2016/09/19: contoh Berubah menggunakan callback ref per bimbingan dari para refatribut String docs.

Ross Allen
sumber
Jadi, satu-satunya cara untuk berkomunikasi antara dua komponen anak adalah dengan memiliki referensi dan melalui metode proxy pada orang tua biasa?
elQueFaltaba
15
Bereaksi mendorong komponen yang digerakkan oleh data. Biarkan satu anak memanggil panggilan balik yang mengubah data pada leluhurnya, dan ketika data itu berubah anak yang lain akan mendapatkan yang baru propsdan merender ulang dengan tepat.
Ross Allen
@RossAllen, haha ​​ya, Anda harus menghapus titik koma juga dalam kasus itu.
HussienK
@ HussienK Saya lebih suka menggunakan blok jika fungsi seharusnya tidak memiliki nilai balik jadi maksudnya jelas bagi pengembang berikutnya yang membaca kode. Mengubah itu menjadi {(child) => this._child = child}akan membuat Fungsi yang selalu dikembalikan true, tetapi nilai itu tidak digunakan oleh refatribut React .
Ross Allen
39

Jika Anda ingin memanggil fungsi pada komponen dari luar Bereaksi, Anda dapat memanggil mereka pada nilai balik dari renderComponent:

var Child = React.createClass({…});
var myChild = React.renderComponent(Child);
myChild.someMethod();

Satu-satunya cara untuk mendapatkan pegangan ke instance Komponen Bereaksi di luar Bereaksi adalah dengan menyimpan nilai pengembalian React.renderComponent. Sumber .

Sjoerd
sumber
1
sebenarnya ini bekerja untuk react16. Metode render ReactDOM mengembalikan referensi ke komponen (atau mengembalikan nol untuk komponen stateless).
Vlad Povalii
37

Atau, jika metode pada Child benar-benar statis (bukan produk dari alat peraga saat ini, nyatakan) Anda dapat mendefinisikannya staticsdan kemudian mengaksesnya seperti halnya Anda menggunakan metode kelas statis. Sebagai contoh:

var Child = React.createClass({
  statics: {
    someMethod: function() {
      return 'bar';
    }
  },
  // ...
});

console.log(Child.someMethod()) // bar
Paul O'Shannessy
sumber
1
Sumber untuk ini ada di sini .
tirdadc
7

Pada React 16.3 React.createRefdapat digunakan, (digunakan ref.currentuntuk mengakses)

var ref = React.createRef()

var parent = <div><Child ref={ref} /> <button onClick={e=>console.log(ref.current)}</div>

React.renderComponent(parent, document.body)
Jay
sumber
4

Sejak Bereaksi 0.12 API sedikit berubah . Kode yang valid untuk menginisialisasi myChild adalah sebagai berikut:

var Child = React.createClass({…});
var myChild = React.render(React.createElement(Child, {}), mountNode);
myChild.someMethod();
Yevgen Safronov
sumber
1

Anda juga bisa melakukannya seperti ini, tidak yakin apakah itu rencana yang bagus: D

class Parent extends Component {
  handleClick() {
    if (this._getAlert !== null) {
      this._getAlert()
    }
  }

  render() {
    return (
      <div>
        <Child>
        {(getAlert, childScope) => (
          <span> {!this._getAlert ? this._getAlert = getAlert.bind(childScope) : null}</span>
        )}
        </Child>
        <button onClick={() => this.handleClick()}> Click me</button>
      </div>
      );
    }
  }

class Child extends Component {
  constructor() {
    super();
    this.state = { count: 0 }
  }

  getAlert() {
    alert(`Child function called state: ${this.state.count}`);
    this.setState({ count: this.state.count + 1 });
  }

  render() {
    return this.props.children(this.getAlert, this)
  }
}
swennemen
sumber
1

Seperti yang disebutkan dalam beberapa komentar, ReactDOM.rendertidak lagi mengembalikan instance komponen. Anda dapat meneruskan refpanggilan balik ketika merender root komponen untuk mendapatkan instance, seperti:

// React code (jsx)
function MyWidget(el, refCb) {
    ReactDOM.render(<MyComponent ref={refCb} />, el);
}
export default MyWidget;

dan:

// vanilla javascript code
var global_widget_instance;

MyApp.MyWidget(document.getElementById('my_container'), function(widget) {
    global_widget_instance = widget;
});

global_widget_instance.myCoolMethod();
mgalg
sumber
-1

Cara lain sangat mudah:

fungsi di luar:

function funx(functionEvents, params) {
  console.log("events of funx function: ", functionEvents);
  console.log("this of component: ", this);
  console.log("params: ", params);
  thisFunction.persist();
}

Ikatkan itu:

constructor(props) {
   super(props);
    this.state = {};
    this.funxBinded = funx.bind(this);
  }
}

Silakan lihat tutorial lengkap di sini: Cara menggunakan "ini" dari Komponen Bereaksi dari luar?

Hou Soune
sumber