reactjs - expose react component methods outside react tree

天大地大妈咪最大 提交于 2020-01-03 17:32:54

问题


Question:

How can I expose a react component's methods to other places?

For example, I want to call React-Router's this.context.router.push(location) from an element outside of React.

Perhaps I could add a React component's method to the window object so it can be called from any generic DOM event listener or even the console?

Background/Use Case:

I want to use jQuery DataTables in my React app because it provides many plugins and config which are still unavailable in the React ecosystem.

I started from an existing React datatable component (implementation below).

The original provides nice option to pass a render function which can, for example, render other React components inside the cells. Below, the cells in the 'Product Name' column are rendered as React-Router < Link /> components.

    const data =  [
        { 
          product_id: '5001', 
          product_price: '$5', 
          product_name: 'Apple'
         },
         ...
      ];

    const renderUrl =
      (val, row) => {
        return (<Link to={`/product/${row.product_id}`}>{row.product_name}</Link>);
      };

    const columns = [
        { title: 'Product Name', prop: 'product_id', render: renderUrl },
        { title: 'Price', prop: 'product_price' },
      ];

    <DataTable
      className="datatable-container"
      columns={columns}
      initialData={data}
    />

What I've done to modify the existing component involves hiding the table from React's DOM diffing algorithm, since it would otherwise break when jQuery DataTables modifies the DOM.

  1. Move the component's render() code into a custom method getDtMarkup() on the class (outside of the react lifecycle).
  2. render() now outputs an empty div with a ref and id

      render() {
        return (
          <div>
            <div ref="dtContainer" id="dtContainer"></div>
          </div>
        );
      }
    
  3. componentDidMount uses ReactDomServer.renderToStaticMarkup to turn a React component into plain, non-react markup and appends this to the #dtContainer div from render(). Finally jQuery DataTables initializes the rendered table html as a fancy 'jQuery DataTable'.

    componentDidMount() {
    
      let table = this.getDTMarkup();
      let dtContainer = this.refs.dtContainer;
      let renderedTable = ReactDOMServer.renderToStaticMarkup(table, dtContainer);
    
      $('#dtContainer').append(renderedTable);
    
      let jqueryTable = $('#dt'); // hard coded in getDTMarkup() for now
    
      // Turn html table into a jQuery DataTable with desired config options
      jqueryTable.DataTable({
        dom: '<"html5buttons"B>lTfgitp',
        buttons: [
          'copy', 'csv', 'excel', 'pdf', 'print'
        ],
        "pagingType": 'numbers',
        "bAutoWidth": false,
        "bDestroy": true,
        "fnDrawCallback": function() {
          console.log('datatables fnDrawCallback');
        }
      });
    }
    

src https://github.com/alecperkey/react-jquery-datatables/blob/master/src/Table.js#L89-L111

The limitation that has me asking this question is that I am now unable to use React components such as < Link /> inside of this static, non-React markup. I am using < a href=""> for now, but this will reload the page, which is slower and causes the white flash of the browser.


回答1:


There are several ways to wire up React components with the "outer application"

You can pass methods as props to your component like:

const foo = function(){
  alert(1)
}

class HelloWorldComponent extends React.Component {
  render() {
    return (      
      <h1 onClick={(e) => this.props.cb()}>Hello {this.props.name}</h1>      
    );
  }
}

React.render(
  <HelloWorldComponent cb={foo} name="Joe Schmoe"/>,
  document.getElementById('react_example')
);

http://jsbin.com/zujebirusa/1/edit?js,output

Using global methods attached to the window. Keep in mind that's hard to maintain as it will pollute the global namespace.

window.foo = function(){
  alert(1)
}

class HelloWorldComponent extends React.Component {
  render() {
    return (      
      <h1 onClick={(e) => window.foo()}>Hello {this.props.name}</h1>      
    );
  }
}

React.render(
  <HelloWorldComponent name="Joe Schmoe"/>,
  document.getElementById('react_example')
);

http://jsbin.com/woyokasano/1/edit?js,output

Using ES6 module system in order to keep your codebase tidy with separate scopes

//methods.js

export function foo() {
    alert(1)
}

import {foo} from './methods';
class HelloWorldComponent extends React.Component {
  render() {
    return (      
      <h1 onClick={(e) => foo()}>Hello {this.props.name}</h1>      
    );
  }
}

React.render(
  <HelloWorldComponent name="Joe Schmoe"/>,
  document.getElementById('react_example')
);


来源:https://stackoverflow.com/questions/37758834/reactjs-expose-react-component-methods-outside-react-tree

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!