-
-
Couldn't load subscription status.
- Fork 16
Open
Description
I've really simple code to render a Tree :
import React from 'react';
import Tree from "./components/Tree";
class App extends React.Component{
treeRef = React.createRef();
state={
data : {
...
}
}
onUpdate = (node) => {
console.debug(node)
this.setState({ node: node });
};
render() {
return(
<div>
<Tree
ref={this.treeRef}
onUpdate={this.onUpdate}
data={this.state.data}
/>
</div>
)
}
}
export default App;
But when I try to render this data :
{
id: 'fruit',
name: 'Fruit',
children: [{
id: 'apple',
name: 'Apple'
},{
id: 'banana',
name: 'Banana',
children: [{
id: 'cherry',
name: 'Cherry'
}]
}]
}
And when trying to render this data :
{
id: 'fruit',
name: 'Fruit',
children: [{
id: 'apple',
name: 'Apple'
}{
id: 'komola',
name: 'komola'
},{
id: 'banana',
name: 'Banana',
children: [{
id: 'cherry',
name: 'Cherry'
}]
}]
}
When changing the tree structure some child renders, some doesn't
And Tree.js is almost as it is in example, still here is the code
Expand :
import Checkbox from '@trendmicro/react-checkbox';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import React, { Component } from 'react';
import InfiniteTree from 'react-infinite-tree';
const renderTreeNode = ({ node, tree, toggleState, onUpdate }) => (
<TreeNode
selected={node.state.selected}
depth={node.state.depth}
onClick={(event) => {
tree.selectNode(node);
}}
>
<Toggler
state={toggleState}
onClick={(event) => {
event.stopPropagation();
if (toggleState === 'closed') {
tree.openNode(node);
} else if (toggleState === 'opened') {
tree.closeNode(node);
}
}}
/>
<Checkbox
checked={node.state.checked}
indeterminate={node.state.indeterminate}
onClick={(event) => {
event.stopPropagation();
}}
onChange={(event) => {
tree.checkNode(node);
onUpdate(node);
}}
/>
<Clickable>
<Icon state={toggleState} />
<Text>{node.name}</Text>
</Clickable>
{(node.loadOnDemand && node.children.length === 0 && !node.state.loading) &&
<i className="fa fa-fw fa-ellipsis-v" />
}
{node.state.loading && <Loading />}
</TreeNode>
);
class Tree extends Component {
static propTypes = {
onUpdate: PropTypes.func
};
treeRef = React.createRef();
tree = null;
componentDidMount() {
const { tree } = this.treeRef.current;
// Select the first node
tree.selectNode(tree.getChildNodes()[0]);
}
render() {
console.debug(this.props.data)
const { onUpdate } = this.props;
if (this.treeRef.current) {
this.tree = this.treeRef.current.tree;
}
return (
<InfiniteTree
ref={this.treeRef}
style={{
border: '1px solid #ccc'
}}
autoOpen
selectable
tabIndex={0}
data={this.props.data}
height="100%"
width={400}
rowHeight={30}
shouldLoadNodes={(node) => {
return !node.hasChildren() && node.loadOnDemand;
}}
loadNodes={(parentNode, done) => {
const suffix = parentNode.id.replace(/(\w)+/, '');
const nodes = [
{
id: 'node1' + suffix,
name: 'Node 1'
},
{
id: 'node2' + suffix,
name: 'Node 2'
}
];
setTimeout(() => {
done(null, nodes);
}, 1000);
}}
shouldSelectNode={(node) => { // Defaults to null
const { tree } = this.treeRef.current;
if (!node || (node === tree.getSelectedNode())) {
return false; // Prevent from deselecting the current node
}
return true;
}}
onKeyUp={(event) => {
console.log('onKeyUp', event.target);
}}
onKeyDown={(event) => {
const { tree } = this.treeRef.current;
console.log('onKeyDown', event.target);
event.preventDefault();
const node = tree.getSelectedNode();
const nodeIndex = tree.getSelectedIndex();
if (event.keyCode === 37) { // Left
tree.closeNode(node);
} else if (event.keyCode === 38) { // Up
const prevNode = tree.nodes[nodeIndex - 1] || node;
tree.selectNode(prevNode);
} else if (event.keyCode === 39) { // Right
tree.openNode(node);
} else if (event.keyCode === 40) { // Down
const nextNode = tree.nodes[nodeIndex + 1] || node;
tree.selectNode(nextNode);
}
}}
onScroll={(scrollOffset, event) => {
const child = event.target.firstChild;
const treeViewportHeight = 400;
console.log((scrollOffset / (child.scrollHeight - treeViewportHeight) * 100).toFixed(2));
console.log('onScroll', scrollOffset, event);
}}
onContentWillUpdate={() => {
console.log('onContentWillUpdate');
}}
onContentDidUpdate={() => {
const { tree } = this.treeRef.current;
console.log('onContentDidUpdate');
onUpdate(tree.getSelectedNode());
}}
onOpenNode={(node) => {
console.log('onOpenNode:', node);
}}
onCloseNode={(node) => {
console.log('onCloseNode:', node);
}}
onSelectNode={(node) => {
console.log('onSelectNode:', node);
onUpdate(node);
}}
onWillOpenNode={(node) => {
console.log('onWillOpenNode:', node);
}}
onWillCloseNode={(node) => {
console.log('onWillCloseNode:', node);
}}
onWillSelectNode={(node) => {
console.log('onWillSelectNode:', node);
}}
>
{({ node, tree }) => {
const hasChildren = node.hasChildren();
let toggleState = '';
if ((!hasChildren && node.loadOnDemand) || (hasChildren && !node.state.open)) {
toggleState = 'closed';
}
if (hasChildren && node.state.open) {
toggleState = 'opened';
}
return renderTreeNode({ node, tree, toggleState, onUpdate });
}}
</InfiniteTree>
);
}
}
export default Tree;
const defaultRowHeight = 30;
const TreeNode = styled.div`
cursor: default;
position: relative;
line-height: ${({ rowHeight = defaultRowHeight }) => rowHeight - 2}px;
background: ${props => props.selected ? '#deecfd' : 'transparent'};
border: ${props => props.selected ? '1px solid #06c' : '1px solid transparent'};
padding-left: ${props => props.depth * 18}px;
.dropdown {
visibility: hidden;
}
&:hover {
background: #f2fdff;
.dropdown {
visibility: inherit;
}
}
`;
const Icon = ({ state, ...props }) => (
<span {...props}>
{{
'opened': (<i className="fa fa-fw fa-folder-open-o" />),
'closed': (<i className="fa fa-fw fa-folder-o" />),
}[state] || (<i className="fa fa-fw fa-file-o" />)}
</span>
);
const Toggler = styled(({ state, ...props }) => (
<a {...props}>
{(state === 'closed') &&
<i className="fa fa-fw fa-chevron-right" />
}
{(state === 'opened') &&
<i className="fa fa-fw fa-chevron-down" />
}
</a>
))`
color: #333;
display: inline-block;
text-align: center;
margin-right: 2px;
`;
const Clickable = styled.div`
display: inline-block;
cursor: pointer;
`;
const Text = styled.span`
margin-left: 0 2px;
user-select: none;
`;
const Loading = () => (
<i className="fa fa-fw fa-spin fa-spinner" />
);
Metadata
Metadata
Assignees
Labels
No labels

