Извините, если это глупый/очевидный вопрос, я новичок в Javascript/React. Я пытаюсь создать меню, заполненное объектами JSON, которые я получаю от вызова API. Поскольку данные JSON представляют собой набор вложенных объектов (я говорю о сотнях объектов), я понял, как рекурсивно вызывать объекты и отображать их в неупорядоченном списке. Кажется, я не могу понять, как добавить функцию onClick, которая при нажатии будет показывать следующий уровень во вложенных объектах.
Я предоставлю несколько скриншотов, чтобы дать вам представление о том, что у меня есть и чего я пытаюсь достичь. Часть рекурсии сбивает меня с толку, как я могу заставить это работать. У кого-нибудь есть идеи?
class Menu extends React.Component {
state = {
categories: []
};
makeMenuLayer = layer => {
const layerKeys = Object.entries(layer).map(([key, value]) => (
<ul>
{key}
{this.makeMenuLayer(value)}
</ul>
));
return <div>{layerKeys}</div>;
};
componentDidMount() {
axios.get("https://www.ifixit.com/api/2.0/categories").then(response => {
this.setState({ categories: response.data });
});
}
render() {
const { categories } = this.state;
return <div>{this.makeMenuLayer(categories)}</div>;
}
}
это то, что в настоящее время отображается с этим кодом. Я пытаюсь сделать так, чтобы отображался только первый слой объектов, а затем при нажатии на каждый элемент отображался следующий уровень. Например, если я нажимаю «Одежда», отображаются «Аксессуары», «Одежда», «Очки» и т. д., а если я нажимаю «Аксессуары», отображаются галстук и зонт.
вот скриншот данных, с которыми я работаю, отображаемых в консоли




![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Это можно сделать несколькими способами, однако общая идея состоит в том, чтобы отслеживать дополнительное состояние, чтобы определить, какой слой в иерархии меню в данный момент виден, а какой нет.
Быстрый и достаточно простой способ сделать это — добавить дополнительную карту под названием hidden к состоянию ваших компонентов, которая будет отслеживать видимость слоев меню в вашем дереве меню.
Что-то вроде этого может сработать для вас:
class Menu extends React.Component {
state = {
categories: [],
/* Add extra state to track which layers are visible or not */
hidden: {}
};
/* Define a local helper function that toggles the layer by key */
toggleMenuLayer = (key) => {
/* A state change is required to cause a re-render of the menu */
this.setState(state => {
const { hidden } = state
const isHidden = hidden[ key ];
/* Add or update hidden state for key in hidden map */
return { hidden : { ...hidden, key : !isHidden }}
});
}
/* Define a local helper function that determines if a layer is visible by its key */
isLayerToggled = (key) => {
/* If "not" hidden then layer is visible, or "toggled" */
return !this.state.hidden[ key ]
}
makeMenuLayer = (parentKey, layer) => {
const layerKeys = Object.entries(layer).map(([key, value]) => {
/* Compose a unique key for this item based on it's position in the hierarchy */
const itemKey = `${parentKey}.${key}`;
return (
<ul>
{ /* Add a toggle button for this layer */ }
<button onClick = {() => this.toggleMenuLayer(itemKey)}>{key}</button>
{ /* If layer is toggled then display it's contents */ }
{ this.isLayerToggled(itemKey) && this.makeMenuLayer(value) }
</ul>
)
});
return <div>{layerKeys}</div>;
};
componentDidMount() {
axios.get("https://www.ifixit.com/api/2.0/categories").then(response => {
this.setState({ categories: response.data });
});
}
render() {
const { categories } = this.state;
return <div>{this.makeMenuLayer(categories)}</div>;
}
}
Надеюсь, комментарии в коде помогут!
Вероятно, не самый эффективный, но я просто подумал об использовании состояния для скрытия/отображения вложенных объектов.
Попробуй это
import React from 'react'
class Menu extends React.Component {
state = {
categories: [],
objectKeys: null,
tempKeys: []
}
makeMenuLayer = layer => {
const { objectKeys } = this.state
const layerKeys = Object.entries(layer).map(([key, value]) => (
<ul key = {key}>
<div onClick = {() => this.handleShowMore(key)}>{key}</div>
{objectKeys[key] && this.makeMenuLayer(value)}
</ul>
))
return <div>{layerKeys}</div>
}
handleShowMore = key => {
this.setState(prevState => ({
objectKeys: {
...prevState.objectKeys,
[key]: !this.state.objectKeys[key]
}
}))
}
initializeTempKeys = layer => {
Object.entries(layer).map(([key, value]) => {
const newTempKeys = this.state.tempKeys
newTempKeys.push(key)
this.setState({ tempKeys: newTempKeys })
this.initializeTempKeys(value)
}
)
}
initializeObjectKeys = () => {
const { tempKeys } = this.state
let tempObject = {}
tempKeys.forEach(tempKey => {
tempObject[tempKey] = true
})
this.setState({ objectKeys: tempObject })
}
async componentDidMount () {
const res = await fetch('https://www.ifixit.com/api/2.0/categories')
const categories = await res.json()
this.initializeTempKeys(categories)
this.initializeObjectKeys()
this.setState({ categories })
}
render () {
const { categories } = this.state
return <div>{this.makeMenuLayer(categories)}</div>
}
}
export default Menu
Вы можете добавить чекер для value. Если это не пустой массив, верните какой-нибудь значок. Что-то вроде {value.length > 0 && <div>arrow</div>}
Эй, Райан, еще раз спасибо за вашу помощь. Мне было интересно, не могли бы вы помочь мне с этим. Я хочу добавить стрелки рядом с каждым элементом, под которым находится еще один слой (по сути, если у этого элемента есть дочерние элементы, отобразите стрелку, чтобы указать это). Ты знаешь, я бы сделал это здесь?