【问题标题】:Push list of elements to component in React将元素列表推送到 React 中的组件
【发布时间】:2020-06-02 04:18:48
【问题描述】:

我想构建一个类似于此图像中的侧边栏组件: 我不想通过道具将子组件作为带有文本值的对象传递,而是为列表中每个元素中的每个键值对创建一个单独的组件。例如:如果列表有 3 个元素,则列表中的每个元素应该有 3 个组件。

到目前为止,这是我的代码:

sidebarcomponents.js:

import React from 'react'

function SidebarComponents({ name, title, selected, onSelect }) {
  const style = {
    cursor: 'pointer'
  }

  return (
    <div
      name={name}
      title={title}
      style={style}
      onClick={() => {
        if (onSelect) onSelect(name)
      }}
    >
                   
    </div>
  )
}

export default SidebarComponents

sidebar.js:


import React, { useEffect, useState } from 'react'
import SidebarComponents from '../../components/Sidebar1/Sidebar'

function Sidebar({ onChange }) {
  const [selectedComponent, setSelectedComponent] = useState({
    componentsName: [
      { name: 'Overview', title: 'Overview' },
      { name: 'SPO2', title: 'SPO2' }
    ]
  })

  return (
    <div>
      {selectedComponent.componentsName.map(componentsName => {
        return (
          <SidebarComponents
            name={componentsName.name}
            title={componentsName.title}
          />
        )
      })}
    </div>
  )
}

export default Sidebar

如何更改我的代码以映射子组件列表而不是代表它们的对象列表?

我希望我的问题很清楚。

【问题讨论】:

  • 定义你的问题。
  • @BhojendraRauniyar 我的问题是我做不到代码是错误的,它没有给我想要的东西,我有一个包含名称和标题的列表,我想创建一个列表中每个元素的组件(因此,例如,如果我有概述和警报,它将创建两个组件,一个用于具有名称概述和标题概述的概述,另一个具有警报

标签: reactjs components


【解决方案1】:

您需要在组件内部的 DIV 中呈现名称,而不是将其作为道具传递给 div 之类的

function SidebarComponents({name,title,selected,onSelect}) {

    const style={
        cursor: "pointer"
    };

    return (
        <div 
            title = {title}
            style={style}
            onClick={() => {if (onSelect) onSelect(name)}}
        >
           {name}
        </div>
    )

}

在映射后渲染它时,还将 onSelect 和 selected 属性传递给 SidebarComponents

【讨论】:

    【解决方案2】:

    @shubham-khatri 的回答是正确的:您需要在组件中包含文本。

    下面是使用 render props 和 hooks 的更深入的解决方案——我建议阅读链接的文档,因为钩子和渲染道具很棒。请注意,钩子仅从 React 16.8 开始可用。

    简单来说,在下面的示例中,侧边栏使用父组件提供的render 属性进行渲染:App。在SidebarComponent 的render 属性中,该函数表示要渲染Title 和Name 组件。来自map 函数的name 用作onClick 处理程序的参数,并将selected 设置为true 或false,而无需将选定的组件对象传递给侧边栏。

    如果您想提供侧边栏可以渲染的组件的主列表,然后传递应该在 props 中渲染的组件,那么您将必须过滤 componentsName 数组,以便仅在SidebarComponent 的道具。

    import React from 'react'
    import ReactDOM from 'react-dom'
    
    /**
     * Title component
     * @param {string=''} props.title
     */
    const Title = ({ title = '' }) => <h2>{title}</h2>
    
    /**
     * Name component
     * @param {string=''} props.name
     */
    const Name = ({ name = '' }) => <div>{name}</div>
    
    /**
     * SidebarComponent styles
     */
    const style = {
      cursor: 'pointer'
    }
    
    /**
     * SidebarComponent classes
     */
    const classes = {
      selected: {
        backgroundColor: '#00ff00'
      }
    }
    
    /**
     * @func SidebarComponent
     * @param {string=''} name
     * @param {function} onClick
     * @param {boolean=false} selected
     * @param {string=''} title
     * @returns {React.Node} react component that returns a div
     *  containing two other components: Title and Name
     */
    const SidebarComponent = ({
      name = '',
      onClick,
      selected = false,
      title = ''
    }) => (
      <div
        onClick={onClick && onClick}
        style={{
          ...style,
          ...(selected ? classes.selected : {})
        }}
      >
        <Title title={title} />
        <Name name={name} />
      </div>
    )
    
    /**
     * @func Sidebar
     * @param {Array[{title: string, name: string}]} componentsName an
     *  arry of components to render inside the sidebar, as SidebarComponents
     * @param {function} renderProp render function that dictates
     *  what to render inside of the sidebar
     * @returns {Node} returns the calling of the renderProp function
     */
    const Sidebar = ({ componentsName, render }) => {
      const [selectedComponentName, setSelectedComponentName] = React.useState(null)
      const handleClick = name => setSelectedComponentName(name)
      return (
        <div id="sidebar">
          {render({
            selectedComponentName,
            handleClick
          })}
        </div>
      )
    }
    
    /**
     * An array of the components to render inside the Sidebar
     */
    const componentsName = [
      { name: 'Overview', title: 'Overview' },
      { name: 'SPO2', title: 'SPO2' }
    ]
    
    /**
     * @func App
     * @returns {React.Node} a react component that renders the sidebar
     */
    const App = () => (
      <Sidebar
        render={({ selectedComponentName, handleClick }) =>
          componentsName.map(({ name, ...props }, index) => (
            <SidebarComponent
              selected={name === selectedComponentName}
              key={`sidebar-component-${index}`}
              onClick={() => handleClick(name)}
              {...{
                name,
                ...props
              }}
            />
          ))
        }
      />
    )
    
    ReactDOM.render(<App />, document.getElementById('container'))
    
    

    演示

    https://codesandbox.io/s/react-playground-wnxer?file=/index.js

    在此演示中,您可以单击任一菜单项,然后看到所选项目将背景颜色更改为绿色。

    【讨论】:

    • @mouhamad 不客气。请注意,这对于您的用例来说可能是多余的。 Title 和 Name 组件不需要存在,因为它们是当前编写的——它们可以组合成单个 SidebarComponent。不过,这是一个有用的学习模式——确保尽可能阅读 hooks 和 renderProps! ?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-19
    • 1970-01-01
    • 1970-01-01
    • 2013-01-21
    • 2017-03-27
    • 1970-01-01
    相关资源
    最近更新 更多