Как получить доступ к обработчикам событий DOM для JSX-компонентов в серверном режиме

Я создаю простой статический механизм просмотра с использованием React с целью рендеринга статической разметки HTML и создания js файла, заполненного этими DOM-событиями компонентов (onClick и т.д.).

То, как я делаю первую часть, - это указать указанный JSX файл, который выглядит, например, следующим образом:

import React from 'React';

export default class Test extends React.Component {

    clicked() {
        alert('Clicked the header!');
    }

    render() {
        return (
            <html>
                <head>
                    <title>{this.props.title}</title>
                </head>
                <body>
                    <h1 onClick={this.clicked}>click me!!!</h1>
                </body>
            </html>
        );
    }
}

Затем я передаю JSX файл через NodeJS-бэкэнд следующим образом:

let view = require('path-to-the-jsx-file');
view = view.default || view;

const ViewElement = React.createFactory(view);
let output = ReactDOMServer.renderToStaticMarkup(ViewElement(props));

Он отлично работает для статического HTML. Но мне интересно, есть ли способ получить доступ ко всем компонентам, используемым в JSX файле в массиве или что-то еще, что я мог бы использовать для проверки того, какие события связаны и к каким обработчикам.

Итак, в этом примере, можно ли получить <h1> -tag onClick -handler? Возможно ли это сделать?

Ответ 1

После лота общения я придумал решение, которое работает очень хорошо.

Если я создаю свой собственный экземпляр ReactElement, который я хочу отобразить (в примере ViewElement(props)), я могу затем визуализировать элемент, используя его стандартную render -функцию:

let element = ViewElement(props);
let instance = new element.type();
let render = instance.render();

Отсюда я могу пройти через все реквизиты для этого элемента, так что, скажем, onClick -handlers будут в render.props.

Так что я делаю это, чтобы проверить каждую опцию, если ключ соответствует имени реакции-события (например, onClick, onDragEnd, onDragEnter и т.д.). Если это так, и значение этого свойства имеет функцию типа - у меня есть имя события и его обработчик-функция:

Object.keys(render.props).map((key) => {
    if (bigArrayOfAllTheEventNames.indexOf(key) !== -1) {
        item.events[key] = render.props[key];//check if type is function.
    }
});

Затем я также повторяю рекурсивно через render.props.children, чтобы охватить все дочерние компоненты и добавить каждый компонент, который имеет события в массив.

Единственная проблема заключалась в том, что мне нужен способ привязать обработанную DOM-строку к обработчикам javascript, которые у меня теперь есть. Для этого я добавил необходимость использовать собственный DOM-атрибут, который затем можно использовать для идентификации компонента с чем-то вроде этого

$("[data-id=value]").on({event-name}, {it JS-handler}).

Это может быть еще не совсем идеально, но я думаю, что это лучшее решение там.

Ответ 2

Чтобы получить функцию как строку из события onClick, мы хотим следующее:

  • DOM элемента
    • Мы можем получить это, добавив атрибут ref в наш элемент h1
  • Имя функции, передаваемой в событие onClick (нажато)
  • Сама функция из строки, содержащей имя функции
    • Поскольку мы удобно используем методы в компоненте React, мы можем использовать это ['functionName'] внутри нашего компонента для получения функции.
  • Строковая версия функции

import React from 'React';

export default class Test extends React.Component {
    componentDidMount() {

        // Gets the name of the function passed inside onClick()
        const nameBound = this.element.props.onClick.name;

        // Removes 'bound ' from the function name (-> clicked)
        const nameString = nameBound.replace('bound ', '');

        // Gets the function from the function name as a string
        const convertedFunction = this[nameString];

        // Converts the function into string
        const stringifiedFunction = convertedFunction.toString();
        console.log(functionString);
    }

    clicked() {
        alert('Clicked the header!');
    }

    render() {
        return (
            <html>
                <head>
                    <title>{this.props.title}</title>
                </head>
                <body>
                    <h1 ref={(element) => { this.element = element; }} onClick={this.clicked}>click me!!!</h1>
                </body>
            </html>
        );
    }
}