วิธีการเข้าถึงวิธีการส่วนประกอบจาก "นอก" ใน ReactJS?


183

เหตุใดฉันจึงไม่สามารถเข้าถึงวิธีส่วนประกอบจาก“ ภายนอก” ใน ReactJS ได้ ทำไมมันเป็นไปไม่ได้และมีวิธีใดที่จะแก้ปัญหาได้?

พิจารณารหัส:

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

บางทีคุณอาจจำเป็นPubsub?
slideshowp2

คำตอบ:


203

ตอบสนองให้อินเตอร์เฟซสำหรับสิ่งที่คุณกำลังพยายามที่จะทำผ่านทางที่แอตทริบิวต์ref กำหนดองค์ประกอบ a refและcurrentแอตทริบิวต์ของมันจะเป็นองค์ประกอบที่กำหนดเองของคุณ:

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

หมายเหตุ : สิ่งนี้จะใช้ได้เฉพาะในกรณีที่คอมโพเนนต์ย่อยถูกประกาศเป็นคลาสตามเอกสารที่พบได้ที่นี่: https://facebook.github.io/react/docs/refs-and-the-dom.html#adding-a- เตะต่อ-a-ระดับองค์ประกอบ

อัปเดต 2019-04-01: เปลี่ยนตัวอย่างเพื่อใช้คลาสและทำเอกสารตอบโต้ล่าสุดcreateRef

ปรับปรุง 2016/09/19: ตัวอย่างเช่นการเปลี่ยนแปลงที่จะใช้โทรกลับเตะต่อคำแนะนำจากString แอตทริบิวต์เอกสารref


ดังนั้นวิธีเดียวที่จะสื่อสารระหว่างสององค์ประกอบย่อยจะมีทั้งการอ้างอิงและการใช้วิธีพร็อกซีบนผู้ปกครองทั่วไป?
elQueFaltaba

15
React กระตุ้นส่วนประกอบที่ขับเคลื่อนด้วยข้อมูล ให้เด็กคนหนึ่งโทรกลับที่เปลี่ยนแปลงข้อมูลในบรรพบุรุษของมันและเมื่อข้อมูลนั้นเปลี่ยนไปเด็กคนอื่นจะได้รับสิ่งใหม่propsและแสดงผลใหม่อย่างเหมาะสม
Ross Allen

@RossAllen ฮ่าฮ่าใช่คุณต้องลบเครื่องหมายอัฒภาคด้วยเช่นกัน
HussienK

@HussienK ฉันชอบที่จะใช้บล็อกถ้าฟังก์ชั่นไม่ควรมีค่าตอบแทนดังนั้นเจตนาจะชัดเจนสำหรับนักพัฒนาคนต่อไปที่อ่านรหัส การเปลี่ยนเป็น{(child) => this._child = child}จะสร้างฟังก์ชั่นที่ส่งคืนเสมอtrueแต่ค่าดังกล่าวจะไม่ถูกใช้โดยrefแอตทริบิวต์ของ React
Ross Allen

39

หากคุณต้องการเรียกใช้งานฟังก์ชั่นบนส่วนประกอบจากนอกทำปฏิกิริยาคุณสามารถเรียกใช้ฟังก์ชันเหล่านี้ด้วยค่าส่งคืนของ renderComponent:

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

วิธีเดียวที่จะได้รับการจัดการกับอินสแตนซ์ส่วนประกอบการทำปฏิกิริยาภายนอกของการทำปฏิกิริยาคือโดยการเก็บค่าตอบแทนของ React.renderComponent แหล่ง


1
ใช้งานได้จริงสำหรับ react16 วิธีการเรนเดอร์ ReactDOM คืนค่าการอ้างอิงไปยังคอมโพเนนต์ (หรือคืนค่า null สำหรับคอมโพเนนต์ที่ไม่มีสถานะ)
Vlad Povalii

37

อีกวิธีหนึ่งหากวิธีการเกี่ยวกับเด็กเป็นแบบคงที่อย่างแท้จริง (ไม่ใช่ผลิตภัณฑ์ของอุปกรณ์ประกอบฉากในปัจจุบันรัฐ) คุณสามารถกำหนดมันstaticsและจากนั้นเข้าถึงได้เช่นเดียวกับวิธีการเรียนแบบคงที่ ตัวอย่างเช่น:

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

console.log(Child.someMethod()) // bar

1
แหล่งที่มาสำหรับเรื่องนี้คือที่นี่
tirdadc

7

React.createRefสามารถใช้ได้ตั้งแต่ React 16.3 (ใช้ref.currentเพื่อเข้าถึง)

var ref = React.createRef()

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

React.renderComponent(parent, document.body)

4

ตั้งแต่ React 0.12 API ที่มีการเปลี่ยนแปลงเล็กน้อย รหัสที่ถูกต้องในการเริ่มต้น myChild จะเป็นดังต่อไปนี้:

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

1

คุณสามารถทำสิ่งนี้ได้เช่นกันไม่แน่ใจว่าเป็นแผนดีหรือไม่: 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)
  }
}

1

ดังที่กล่าวไว้ในความคิดเห็นบางส่วนจะReactDOM.renderไม่ส่งคืนอินสแตนซ์ของคอมโพเนนต์อีกต่อไป คุณสามารถผ่านการrefติดต่อกลับเมื่อแสดงรากของส่วนประกอบเพื่อรับอินสแตนซ์เช่น:

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

และ:

// vanilla javascript code
var global_widget_instance;

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

global_widget_instance.myCoolMethod();

-1

อีกวิธีง่าย ๆ :

ฟังก์ชั่นนอก:

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

ผูกมัน:

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

โปรดดูบทช่วยสอนที่สมบูรณ์ที่นี่: วิธีใช้ "สิ่งนี้" ขององค์ประกอบการตอบโต้จากภายนอก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.