如何在服务器端 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 文件中使用的所有组件,然后我可以使用它来检查绑定了哪些事件以及哪些处理程序。
那么在这个例子中,能够得到<h1>
-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 中,如何将 JSX 与返回更多 JSX 的 JS 函数一起返回?
如何在我的 ag-grid 单元格中放置一个 react jsx 组件