我试图找出如何将react组件作为输入并映射到新的组件树(替换标签并根据需要进行修改)。在这种特定情况下,我想为DOM输出编写一个组件,并将其修改为本机输出。
因此,非常简化的组件可能来自:
<MyComponent>
<p>foo</p>
</MyComponent>
为:
<MyComponent>
<Text>foo</Text>
</MyComponent>
修改单个标签道具的加分点,例如添加style
道具,事件处理程序等等。我知道如果有一个答案,那么它不会是一刀切的。我只是希望对遇到这个用例的一般方法/其他人提出一些指导并将其推进。
答案 0 :(得分:0)
这样的事情似乎运作得相当好,尽管在树下传递样式是一个悬而未决的问题。好吧,至少我们知道从一组标签到另一组标签的转换是可能的。道具https://stackoverflow.com/users/2578335/giles-copp
// traverse.js
import React from 'react';
export function kindOf(node) {
if (node === null || node === undefined || typeof node === 'boolean') {
return 'Empty';
}
if (typeof node === 'string' || typeof node === 'number') {
return 'Text';
}
if (Array.isArray(node)) {
return 'Fragment';
}
const { type } = node;
if (typeof type === 'string') {
return 'DOMElement';
}
return 'ComponentElement';
}
export function defaultTraverse(path) {
const kind = kindOf(path.node);
if (kind === 'Empty') {
return path.node;
}
if (kind === 'Text') {
return path.node;
}
if (kind === 'Fragment') {
return path.node.map(path.traverse);
}
return React.cloneElement(
path.node,
path.node.props,
...path.traverseChildren(),
);
}
export default function traverse(node, visitor) {
const {
Empty = defaultTraverse,
Text = defaultTraverse,
Fragment = defaultTraverse,
DOMElement = defaultTraverse,
ComponentElement = defaultTraverse
} = visitor;
const path = {
node,
kindOf,
defaultTraverse() {
return defaultTraverse(path);
},
traverse(childNode, childVisitor = visitor) {
return traverse(childNode, childVisitor);
},
traverseChildren(childVisitor = visitor) {
return React.Children.toArray(path.node.props.children).map(
(childNode) => path.traverse(childNode, childVisitor)
);
},
visitor
};
if (node === null || node === undefined || typeof node === 'boolean') {
return Empty(path);
}
if (typeof node === 'string' || typeof node === 'number') {
return Text(path);
}
if (Array.isArray(node)) {
return Fragment(path);
}
const { type } = node;
if (typeof type === 'string') {
return DOMElement(path);
}
return ComponentElement(path);
}
// transpile.js
import React from 'react';
import { Image, Text, View } from 'react-native';
import traverse from './traverse';
const viewNodeTypes = ['div'];
const textNodeTypes = ['h1', 'p'];
const inlineNodeTypes = ['span', 'b', 'em'];
const dom2ReactNative = (node) => traverse(node, {
ComponentElement(path) {
if (path.node.type === 'img') {
return React.createElement(
Image,
path.node.props
);
}
},
DOMElement(path) {
if (textNodeTypes.includes(path.node.type)) {
return React.createElement(
Text,
path.node.props,
...path.traverseChildren(),
);
} else if (viewNodeTypes.includes(path.node.type)) {
return React.createElement(
View,
path.node.props,
...path.traverseChildren(),
);
} else if (inlineNodeTypes.includes(path.node.type)) {
return path.node.props.children;
}
return React.cloneElement(
path.node,
path.node.props,
...path.traverseChildren(),
);
}
});
export default dom2ReactNative;