首页 > 解决方案 > 如何使用条件渲染编写干净、可读的 ReactJS 组件?

问题描述

结果没有显示在我的窗口中。我创建了一个用于测试的全局对象:

const obj = {
  onam: [
    {
      name: "name3",
      image: "https://resize.hswstatic.com/w_828/gif/kelp-biofuel.jpg"
    },
    {
      name: "name2",
      image: "https://resize.hswstatic.com/w_828/gif/kelp-biofuel.jpg"
    }
  ],
  christmas: [
    {
      name: "name1",
      image: "https://resize.hswstatic.com/w_828/gif/kelp-biofuel.jpg"
    },
    {
      name: "name0",
      image: "https://resize.hswstatic.com/w_828/gif/kelp-biofuel.jpg"
    }
  ]
}

下面是我在渲染中调用的函数。

const grid = (props) => {
  if (props == "All") {
    const keys = Object.keys(obj);
    // looping through keys
    keys.forEach((key, index) => { 
      // looping through array in keys
      for(let j = 0; j < Object.keys(obj).length; j++) {
        return (
          <div>
            <a><img src={obj[key][j].image}>{obj[key][j].name}</img></a>
          </div>
        )
      }
    });   
  }
}

我知道上面的函数有一些错误,但我无法解决。我{grid("All")}在渲染内部调用。我的目标是显示一个 div,其中包含一个带有标签的所有图像的 div。我想学习一种有条件地渲染组件的干净方法。

标签: javascripthtmlreactjsweb-frontend

解决方案


Ashwin 有几个问题。

  • 您的组件名称应以大写字母开头。
  • 使用数组而不是 object obj。使用数组并循环它们比循环对象更容易。
  • 不要将整个组件包装在 if 语句中。它的坏习惯。
  • props == "All"是错的。props 是一个对象而不是字符串。这是没有渲染的主要原因。该 if 语句将始终返回 false。
  • <img>不带孩子,所以不要传入{obj[key][j].name}img 标签。将结束 img 标签之后的那个位移动到<a>标签中。

我正在重写您的组件并添加一些注释以帮助您学习,但是还有其他几种方法可以达到相同的结果,也许是更好的方法。这对我有用,我发现它更具可读性和更容易理解。

import React from "react"

/* An array of objects is always easier to work than objects with 
multiple arrays as values. You might end up duplicating a few keys like
"festival" in this example, but it will make your life easier.
 */

const arr = [
    {
      festival: "oman",
      name: "name3",
      image: "https://resize.hswstatic.com/w_828/gif/kelp-biofuel.jpg",
    },
    {
      festival: "oman",
      name: "name2",
      image: "https://resize.hswstatic.com/w_828/gif/kelp-biofuel.jpg",
    },
    {
      festival: "christmas",
      name: "name1",
      image: "https://resize.hswstatic.com/w_828/gif/kelp-biofuel.jpg",
    },
    {
      festival: "christmas",
      name: "name0",
      image: "https://resize.hswstatic.com/w_828/gif/kelp-biofuel.jpg",
    },
]

/* 
Always make sure your components are uppercase

De-structure your props with { propName1, propName2 }
because that way you or anybody else looking at your
component immediately can recognize what props are being
passed.
*/
const Grid = ({ whatToRender }) => {
  /*  
  Create a custom render function inside your component if
  you need to render conditionally. Its easier to work with
  debug and maintain. 
  */
  const renderGrid = () => {
    if (whatToRender === "all") { // use === over == because that will check for type equality as well.
      return arr.map((item) => ( // () is equivalent to return () when looping.
        /* Always pass a unique key if you are creating lists or lopping */
        <div key={item.image}> 
          <a>
            <img src={item.image} alt={item.name} />
            {item.name}
          </a>
        </div>
      ))
    }
    if (whatToRender === "onam") {
      return arr.map((item) => {
        if (item.festival === "onam") {
          return (
            <div key={item.image}>
              <a>
                <img src={item.image} alt={item.name} />
                {item.name}
              </a>
            </div>
          )
        }
      })
    }
    if (whatToRender === "christmas") {
      return arr.map((item) => {
        if (item.festival === "christmas") {
          return (
            <div key={item.image}>
              <a> {/* Image tags don't take children they are self-closing */}
                <img src={item.image} alt={item.name} />
                {item.name}
              </a>
            </div>
          )
        }
      })
    } // Return an empty div if none of the cases pass. So, you return valid JSX
    return <div></div>
  }
  return renderGrid() // Finally return your custom render function
}

export default Grid

编辑

再次访问这个问题时,我意识到有更好的方法来编写它。一个更短的版本。它使用上述代码示例中定义的相同 arr。

const Grid = ({ whatToRender }) => {
  const renderGrid = () => {
    return arr.map((item) => {
      if (item.festival === whatToRender || whatToRender === "all") {
        return (
          <div key={item.image}>
            <a>
              <img src={item.image} alt={item.name} />
              {item.name}
            </a>
          </div>
        )
      }
    })
  }
  return renderGrid()
}

export default Grid

使用哪一个?第二个版本不仅因为它更短,而且因为它可以重复使用。如果将来您添加另一个节日arr来说复活节,您只需要更改数组和您传递的道具值。该组件将不需要更改。


推荐阅读