【问题标题】:How to set up onClick function within menu in Reactjs?如何在 Reactjs 的菜单中设置 onClick 功能?
【发布时间】:2019-09-28 20:35:21
【问题描述】:

对不起,如果这是一个愚蠢/显而易见的问题,我是 Javascript/React 的新手。我正在尝试创建一个菜单,其中包含从 API 调用中获得的 JSON 对象。由于 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 json reactjs recursion


    【解决方案1】:

    有很多方法可以做到这一点,但总体思路是跟踪一些额外的状态,以确定菜单层次结构中的哪个层当前可见,哪个不可见。

    一种快速且相当简单的方法是在组件状态中添加一个名为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>;
        }
    }
    

    希望代码中的cmets帮忙!

    【讨论】:

      【解决方案2】:

      可能不是最有效的,但我只是想到使用状态来隐藏/取消隐藏嵌套对象。

      试试这个

      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 &gt; 0 &amp;&amp; &lt;div&gt;arrow&lt;/div&gt;}
      猜你喜欢
      • 2020-10-28
      • 1970-01-01
      • 2012-12-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多