reactjs - выставить методы компонента реакции за пределами дерева реакции

Вопрос:

Как я могу предоставить методы компонента React в других местах?

Например, я хочу вызвать this.context.router.push (местоположение) React-Router из элемента вне React.

Возможно, я мог бы добавить метод компонента React к объекту окна, чтобы его можно было вызывать из любого общего прослушивателя событий DOM или даже из консоли?

Предпосылки / пример использования:

Я хочу использовать jQuery DataTables в своем приложении React, потому что оно предоставляет множество плагинов и конфигураций, которые по-прежнему недоступны в экосистеме 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}
    />

То, что я сделал для изменения существующего компонента, включает в себя скрытие таблицы от алгоритма сравнения DOM React, поскольку в противном случае он сломался бы, когда jQuery DataTables изменяет DOM.

  1. Переместите код компонента render () в настраиваемый метод getDtMarkup () в классе (вне жизненного цикла реакции).
  2. render () теперь выводит пустой div с ref и id

      render() {
        return (
          <div>
            <div ref="dtContainer" id="dtContainer"></div>
          </div>
        );
      }
    
  3. componentDidMount использует ReactDomServer.renderToStaticMarkup для превращения компонента React в простую разметку без реакции и добавляет ее в div #dtContainer из render (). Наконец, 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 =" ">, но это перезагрузит страницу, что будет медленнее и приведет к белой вспышке браузера.


person AlecPerkey    schedule 11.06.2016    source источник


Ответы (2)


Вот как мне удалось предоставить метод из компонента реакции в «глобальную» область видимости или за пределами приложения реакции. Я действительно не знаю деталей вашего дела, но это может сработать для вас. Кроме того, я использую хуки, но это также должно работать с устаревшими методами жизненного цикла.

Представьте, что это моя составляющая. Он просто отображает число, управляемое государством.

const MyCount = ({ getMethods }) => {
  const [state, setState] = useState(1);
  useEffect(() => {
    getMethods({ setState });
  }, []);
  return <h1>{state}</h1>;
}

Видите ли, getMethods - ключевая опора для того, чтобы это работало. Эта функция будет выполнена при монтировании компонента и предоставит методы, которые мне нужно предоставить в качестве аргумента. В этом случае метод setState.

А теперь давайте представим, что у меня есть кнопка вне React, которую я хочу использовать для запуска этого метода.

// I want to store the methods in this variable
let globalMethods;

// When rendering the react component I pass the prop `getMethods` 
// that will assign the returned value
React.render(<MyCount getMethods={methods => globalMethods = methods} />, $someEl);

// Now I can use it outside
$("#myButton").click(() => {
  globalMethods.setState(2);
})

Надеюсь, это поможет. Или вам это даже больше не нужно, так как уже прошло 3,9 года.

person Juan Solano    schedule 11.02.2020
comment
Это, безусловно, помогло мне, это отличное использование. Мне это нужно, чтобы получить ответ oauth из всплывающего окна, которое находится в другом домене. - person famouspotatoes; 26.03.2020

Есть несколько способов связать компоненты 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')
);
person vorillaz    schedule 11.06.2016
comment
Вы показали мне, как добавить метод к компоненту React. Но я не об этом спрашиваю. Я пытаюсь привязать существующий метод компонента React к глобальному контексту, например к окну, или к элементу DOM, не относящемуся к React. ... поэтому его можно вызвать из общего прослушивателя событий DOM или даже из консоли. Например, как мне привязать функциональность React-Router this.context.router.push к объекту окна, чтобы мой элемент DOM, не относящийся к React, мог использовать эту функцию? - person AlecPerkey; 11.06.2016