简体   繁体   中英

Access a React component method / state from outside the component

I have embedded a reactjs component into an existing HTML page by referencing it's ID like described in React's tutorial:

ReactDOM.render(
  <Page />,
  document.getElementById('my-react-compnent')
);

Then:

<div id="my-react-compnent></div>

The component is displayed and works as expected.

Now I want to link a button located on that page to my component (to be specific I would like to retrive its state, but for the example even invoking one of its methods would be fine).

In other words - when clicking the outside button, I want to invoke a method from the Page component?

How can I do that?

The Old Recommendation

Assigning the returned value from ReactDOM.render does allow access to the component and it's methods. For example, in a simple app, we might have:

const PageComponent = ReactDOM.render(<Page />, document.getElementById("app"));

which we can then access using PageComponent , and any of its methods can be accessed with PageComponent.METHOD .

However , according to the docs this might be changed or deprecated and is not recommended.

The New Recommendation

The new recommendation is to attach a callback ref to the root element. Using the same example above:

const PageComponent = ReactDOM.render(<Page ref={(pageComponent) => {window.pageComponent = pageComponent}}/>, document.getElementById("app"));

which we can then access using window.pageComponent , and any of its methods can be accessed with window.pageComponent.METHOD .

This also works for child components.

Here's a full example:

 class ChildComponent extends React.Component { constructor(props) { super(props); this.state = { counter: 0 } } returnCounter = () => { return this.state.counter; } increment = (event) => { event.stopPropagation(); this.setState(prevState => { return { counter: prevState.counter + 1 } }) } render() { return ( <div onClick={this.increment}> Child Value - {this.state.counter} - Click to increment </div> ) } } class Page extends React.Component { constructor(props) { super(props); this.state = { counter: 0 } } returnCounter = () => { return this.state.counter; } increment = () => { this.setState(prevState => { return { counter: prevState.counter + 1 } }) } render() { return ( <div onClick={this.increment}> <div>Parent Value - {this.state.counter} - Click to increment</div> <ChildComponent ref={(childComponent) => {window.childComponent = childComponent}}/> </div> ) } } ReactDOM.render(<Page ref={(pageComponent) => {window.pageComponent = pageComponent}} />, document.getElementById("app")); const parentBtn = document.getElementById("parentButton"); parentBtn.addEventListener("click", event => { alert(window.pageComponent.returnCounter()); }); const childBtn = document.getElementById("childButton"); childBtn.addEventListener("click", event => { alert(window.childComponent.returnCounter()); }); 
 <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> <button id="parentButton">Get Parent State</button> <button id="childButton">Get Child State</button> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM