如何在服务器端的React中访问JSX组件的DOM事件处理程序

10
我将使用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>
        );
    }
}

我现在通过NodeJS后端来渲染JSX文件,代码如下:

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>标签的onClick处理程序?是否可能以某种方式实现这一点?

2个回答

3

为了从onClick事件中获取函数作为字符串,我们需要以下内容:

  1. 元素的DOM
    • 我们可以在h1元素上附加ref属性来获得它
  2. 传递到onClick事件中的函数名称(clicked)
  3. 函数本身,从包含函数名称的字符串中获取
    • 由于我们方便地在React组件中使用方法,因此可以使用this['functionName']来获取该函数。
  4. 函数的字符串版本

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>
        );
    }
}

这个方案可行,但难以维护。想象一下,在那个组件中有5-10个处理程序。而且我不确定你如何能够将这些数据送回后端,除非你有一个主组件,其中有一个函数可以以某种方式做到这一点。 - Tokfrans

2

经过很多折腾,我想出了一个相当不错的解决方案。

如果我创建自己的要渲染的ReactElement实例(例如ViewElement(props)),然后使用它的标准render函数来渲染该元素:

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

从这里我可以查看此元素的所有属性,例如,onClick处理程序将在render.props中。

因此,我的做法是检查每个属性是否与React事件名称匹配(例如,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's JS-handler}).

可能还不完美,但我认为这是目前最好的解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接