【问题标题】:Can a React prop type be defined recursively?可以递归定义 React 道具类型吗?
【发布时间】:2015-08-18 03:58:28
【问题描述】:

假设我们正在定义一个将显示一棵树的 React 类。

React.createClass({
    propTypes: {
        tree: treeType
    },
    render: function () {
        // ...
    }
});

这是treeType 的定义,它显然不起作用,但希望能说明我想要表达的意思。

var treeType = React.PropTypes.shape({
    value: React.PropTypes.string,
    children: React.PropTypes.arrayOf(treeType)
})

有没有办法让类型懒惰地引用自己,这样就可以了?

【问题讨论】:

标签: javascript reactjs


【解决方案1】:

这是另一种方法,由jethrolarson on GitHub 提供:

给定递归组件Tree

import React from 'react';

const Tree = ({treeData}) => (
    <div>
        {treeData.nodeName}{' '}
        {treeData.children.map(subTree => (
            <Tree treeData={subTree} />
        ))}
    </div>
);

采用如下所示的树形数据结构

                Root
                /  \
           Child1   Child2
          /     \        \
     GChild1   GChild2   GChild3

(如代码:

const treeData = {
    nodeName: "Root",
    children: [
        {
            nodeName: "Child1",
            children: [
                {nodeName: "GChild1"},
                {nodeName: "GChild2"},
            ]
        },
        {
            nodeName: "Child2",
            children: [
                {nodeName: "GChild3"},
            ]
        },
    ]
};

),

TreepropTypes 可以定义为:

import PropTypes from 'prop-types';

const treeDataShape = {
    nodeName: PropTypes.string.isRequired,
};
treeDataShape.children = PropTypes.arrayOf(PropTypes.shape(treeDataShape));

Tree.propTypes = {
    treeData: PropTypes.shape(treeDataShape),
};

注意所有对treeDataShape 的引用是如何引用同一个对象的。在创建对象后定义children 可以递归地引用同一个对象。

【讨论】:

  • 接受的答案对我来说并不奏效,但参考共享策略却奏效了。 +1
【解决方案2】:

React prop 类型只是一个函数,因此可以像这样懒惰地引用它:

function lazyFunction(f) {
    return function () {
        return f.apply(this, arguments);
    };
}

var lazyTreeType = lazyFunction(function () { 
    return treeType;
});

var treeType = React.PropTypes.shape({
    value: React.PropTypes.string.isRequired,
    children: React.PropTypes.arrayOf(lazyTreeType)
})

完整工作示例的其余代码 (also available as a jsfiddle):

function hasChildren(tree) {
    return !!(tree.children && tree.children.length);
}

var Tree = React.createClass({
    propTypes: {
        tree: treeType
    },
    render: function () {
        return this.renderForest([this.props.tree], '');
    },
    renderTree: function (tree, key) {
        return <li className="tree" key={key}>
            <div title={key}>{tree.value}</div>
            {hasChildren(tree) &&
                this.renderForest(tree.children, key)}
        </li>;
    },
    renderForest: function (trees, key) {
        return <ol>{trees.map(function (tree) {
            return this.renderTree(tree, key + ' | ' + tree.value);
        }.bind(this))}</ol>;
    }
});

var treeOfLife = { value: "Life", children: [
    {value: "Animal", children: [
        {value: "Dog"},
        {value: "Cat"}
    ]},
    {value: "Plant"}
]};

React.render(
    <Tree tree={treeOfLife}/>,
    document.getElementById('tree'));

结果截图:

【讨论】:

  • 不使用 just 的一些原因: var lazyTreeType = function () { return treeType.apply(this, arguments); };
  • @FelipeT。我也很好奇这个
  • @FelipeT。我认为您建议的功能没有问题。答案的方法可能只是为了便于理解和更通用一点。
【解决方案3】:

我创建了类似这样的递归道具类型,它对我有用。让我知道它是否也适合您。 lazyTreeType 函数将被调用多少次,因为对象中有一个 sub。

const lazyTreeType = () => some_props;
const some_props= PropTypes.shape({
  date: PropTypes.string,
  updated: PropTypes.string,
  name: PropTypes.string,
  sub: PropTypes.arrayOf(lazyTreeType),
  type: PropTypes.string,
});

const component_proptype = PropTypes.shape({
  id: PropTypes.string,
  sub: PropTypes.arrayOf(some_props),
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-11
    • 2021-11-01
    相关资源
    最近更新 更多