Как получить доступ к обработчикам событий 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>
);
}
}