首页 文章

reactjs - 在反应树外暴露反应组分方法

提问于
浏览
3

Question:

如何将反应组件的方法暴露给其他地方?

例如,我想从React之外的元素调用React-Router的this.context.router.push(location) .

也许我可以在窗口对象中添加一个React组件的方法,以便可以从任何通用DOM事件监听器甚至控制台调用它?

Background/Use Case:

我想在我的React应用程序中使用jQuery DataTables,因为它提供了许多插件和配置,这些插件和配置在React生态系统中仍然不可用 .

我从现有的React数据表组件开始(下面的实现) .

原始提供了传递渲染函数的不错选项,例如,渲染单元格内的其他React组件 . 下面,“产品名称”列中的单元格呈现为React-Router <Link />组件 .

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

我修改现有组件所做的工作涉及将表隐藏在React的DOM diffing算法中,因为当jQuery DataTables修改DOM时它会破坏 .

  • 将组件的render()代码移动到类的自定义方法getDtMarkup()中(在反应生命周期之外) .

  • render()现在输出一个带有ref和id的空div

render() {
    return (
      <div>
        <div ref="dtContainer" id="dtContainer"></div>
      </div>
    );
  }
  • componentDidMount使用ReactDomServer.renderToStaticMarkup将React组件转换为普通的非反应标记,并将其附加到render()的#dtContainer div中 . 最后,jQuery DataTables将渲染的表html初始化为一个花哨的'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

我问这个问题的限制是我现在无法在这个静态的非React标记中使用诸如<Link />之类的React组件 . 我现在正在使用<a href =“”>,但这会重新加载页面,这会更慢并导致浏览器的白色闪烁 .

1 回答

  • -1

    有几种方法可以将React组件与“外部应用程序”连接起来

    您可以将方法作为道具传递给组件,如:

    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

    使用附加到窗口的全局方法 . 请记住,它很难维护,因为它会污染全局命名空间 .

    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

    使用ES6模块系统,以保持您的代码库与单独的范围整洁

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

相关问题