Suppose we're defining a React class that will display a tree.
React.createClass({
propTypes: {
tree: treeType
},
render: function () {
// ...
}
});
Here's a definition of treeType
that obviously doesn't work but hopefully illustrates what I'm trying to express.
var treeType = React.PropTypes.shape({
value: React.PropTypes.string,
children: React.PropTypes.arrayOf(treeType)
})
Is there a way to let the type refer to itself lazily so this can work?
A React prop type is just a function, so it can be referenced lazily like this:
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)
})
The rest of the code for a complete working example (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'));
Screenshot of the result:
Here's another approach, courtesy of jethrolarson on GitHub:
Given the recursive component Tree
import React from 'react';
const Tree = ({treeData}) => (
<div>
{treeData.nodeName}{' '}
{treeData.children.map(subTree => (
<Tree treeData={subTree} />
))}
</div>
);
that takes a tree data structure like the one below
Root
/ \
Child1 Child2
/ \ \
GChild1 GChild2 GChild3
(as code:
const treeData = {
nodeName: "Root",
children: [
{
nodeName: "Child1",
children: [
{nodeName: "GChild1"},
{nodeName: "GChild2"},
]
},
{
nodeName: "Child2",
children: [
{nodeName: "GChild3"},
]
},
]
};
),
the propTypes
for Tree
can be defined as:
import PropTypes from 'prop-types';
const treeDataShape = {
nodeName: PropTypes.string.isRequired,
};
treeDataShape.children = PropTypes.arrayOf(PropTypes.shape(treeDataShape));
Tree.propTypes = {
treeData: PropTypes.shape(treeDataShape),
};
Note how all of the references to treeDataShape
refer to the same object. Defining children
after the object is created lets you recursively reference the same object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With