Lux*_*Lux 2 javascript recursion reactjs
这是index()我用来从 Markdown 文件返回标题索引的示例函数。正如您所看到的,只有 3 个级别的标题,它很快就会失控。
我尝试了各种递归想法,但最终在create-react-app.
任何人都可以就如何清理它甚至允许无限/更高级别的嵌套提供任何指导吗?
存储一个数组this.state.index,类似于下面的数组。
[
{
label: 'Header title',
children: [
{
label: 'Sub-header title'
children: [...]
}
]
}
]
Run Code Online (Sandbox Code Playgroud)
然后在下面的函数中使用该数据来生成ul索引。
index() {
if ( this.state.index === undefined || !this.state.index.length )
return;
return (
<ul className="docs--index">
{
this.state.index.map((elm,i=0) => {
let key = i++;
let anchor = '#'+elm.label.split(' ').join('_') + '--' + key;
return (
<li key={key}>
<label><AnchorScroll href={anchor}>{elm.label}</AnchorScroll></label>
<ul>
{
elm.children.map((child,k=0) => {
let key = i+'-'+k++;
let anchor = '#'+child.label.split(' ').join('_') + '--' + key;
return (
<li key={key}>
<label><AnchorScroll href={anchor}>{child.label}</AnchorScroll></label>
<ul>
{
child.children.map((grandchild,j=0) => {
let key = i+'-'+k+'-'+j++;
let anchor = '#'+grandchild.label.split(' ').join('_') + '--' + key;
return (
<li key={key}>
<label><AnchorScroll href={anchor}>{grandchild.label}</AnchorScroll></label>
</li>
);
})
}
</ul>
</li>
);
})
}
</ul>
</li>
);
})
}
</ul>
);
}
Run Code Online (Sandbox Code Playgroud)
就像我说的,这是一团糟!我是 React 和编码的新手,如果这是一个愚蠢的问题,我很抱歉。
好像你想要一个组件的递归调用。
例如,组件Item将根据条件(children数组的存在)自行呈现。
运行示例:
const data = [
{
label: 'Header title',
children: [
{
label: 'Sub-header title',
children: [
{ label: '3rd level #1' },
{
label: '3rd level #2',
children: [
{ label: 'Level 4' }
]
}
]
}
]
}
]
class Item extends React.Component {
render() {
const { label, children } = this.props;
return (
<div>
<div>{label}</div>
<div style={{margin: '5px 25px'}}>
{children && children.map((item, index) => <Item key={index} {...item} />)}
</div>
</div>
)
}
}
const App = () => (
<div>
{data.map((item, index) => <Item key={index} {...item} />)}
</div>
);
ReactDOM.render(<App />, document.getElementById('root'));Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>Run Code Online (Sandbox Code Playgroud)
编辑
为了完整起见,我添加了另一个示例,但这次我们在更高级别处理本地组件状态isOpen之外的属性Item。
这可以很容易地移动到redux减速器或任何其他状态管理库,或者只是让更高级别的组件像App在这种情况下管理更改。
因此,要处理递归组件的更改,您可能会编写一个递归处理程序:
const data = [
{
label: 'Header title',
id: 1,
children: [
{
label: 'Sub-header title',
id: 2,
children: [
{ label: '3rd level #1', id: 3 },
{
label: '3rd level #2',
id: 4,
children: [
{ label: 'Level 4', id: 5 }
]
}
]
},
]
},
{
label: 'Header #2',
id: 6,
children: [
{ label: '2nd level #1', id: 7, },
{
label: '2nd level #2',
id: 8,
children: [
{ label: 'Level 3', id: 9 }
]
}
]
}
]
class Item extends React.Component {
toggleOpen = e => {
e.preventDefault();
e.stopPropagation();
const {onClick, id} = this.props;
onClick(id);
};
render() {
const { label, children, isOpen, onClick } = this.props;
return (
<div className="item">
<div
className={`${children && "clickable"}`}
onClick={children && this.toggleOpen}
>
<div
className={`
title-icon
${isOpen && " open"}
${children && "has-children"}
`}
/>
<div className="title">{label}</div>
</div>
<div className="children">
{children &&
isOpen &&
children.map((item, index) => <Item key={index} {...item} onClick={onClick} />)}
</div>
</div>
);
}
}
class App extends React.Component {
state = {
items: data
};
toggleItem = (items, id) => {
const nextState = items.map(item => {
if (item.id !== id) {
if (item.children) {
return {
...item,
children: this.toggleItem(item.children, id)
};
}
return item;
}
return {
...item,
isOpen: !item.isOpen
};
});
return nextState;
};
onItemClick = id => {
this.setState(prev => {
const nextState = this.toggleItem(prev.items, id);
return {
items: nextState
};
});
};
render() {
const { items } = this.state;
return (
<div>
{items.map((item, index) => (
<Item key={index} {...item} onClick={this.onItemClick} />
))}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));Run Code Online (Sandbox Code Playgroud)
.item {
padding: 0 5px;
}
.title-icon {
display: inline-block;
margin: 0 10px;
}
.title-icon::before {
margin: 12px 0;
content: "\2219";
}
.title-icon.has-children::before {
content: "\25B6";
}
.title-icon.open::before {
content: "\25E2";
}
.title-icon:not(.has-children)::before {
content: "\2219";
}
.title {
display: inline-block;
margin: 5px 0;
}
.clickable {
cursor: pointer;
user-select: none;
}
.open {
color: green;
}
.children {
margin: 0 15px;
}Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2612 次 |
| 最近记录: |