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

Posted

技术标签:

【中文标题】如何在服务器端 React 中访问 JSX 组件的 DOM 事件处理程序【英文标题】:How to access DOM event-handlers for JSX-components in server-sided React 【发布时间】:2018-03-23 15:31:22 【问题描述】:

我正在使用 React 构建一个简单的静态视图引擎,目的是呈现静态 html 标记并生成一个填充了该组件 DOM 事件(onClick 等)的 js 文件。

我做第一部分的方式是要求一个指定的 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 文件中使用的所有组件,然后我可以使用它来检查绑定了哪些事件以及哪些处理程序。

那么在这个例子中,能够得到&lt;h1&gt;-tag 的onClick-handler 吗?这甚至有可能以某种方式做到吗?

【问题讨论】:

【参考方案1】:

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

    元素的 DOM 我们可以通过在我们的 h1 元素上附加一个ref 属性来获得它 传递到 onClick 事件(单击)的函数的名称 函数本身来自包含函数名称的字符串 由于我们在 React 组件中方便地使用方法,我们可以在组件中使用 this['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>
        );
    

【讨论】:

这可以工作,但很难维护。想象一下,该组件中有 5-10 个处理程序。而且我不确定你如何能够将这些数据返回到后端,除非你有一个主组件,它有一个以某种方式做到这一点的功能。【参考方案2】:

经过大量的折腾,我想出了一个效果很好的解决方案。

如果我创建自己想要渲染的 ReactElement 实例(在示例中为 ViewElement(props)),然后我可以使用它的标准 render-function 渲染元素:

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's JS-handler).

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

【讨论】:

以上是关于如何在服务器端 React 中访问 JSX 组件的 DOM 事件处理程序的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 React.js 在 JSX 中循环对象

在 React 中,如何将 JSX 与返回更多 JSX 的 JS 函数一起返回?

如何渲染 JSX 元素数组(React 组件)

如何在我的 ag-grid 单元格中放置一个 react jsx 组件

服务器端 React-Redux,Express,没有额外的 ES6 和 JSX 语法

服务器端 React:Babel 不会在服务器上转换 JSX,既不是动态也不是手动转换。为啥?