如何使用条件渲染编写干净、可读的 ReactJS 组件?

How to write clean, readable ReactJS Components with conditional renders?

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

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"
    }
  ]
}

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

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 以及所有带有标签的图像。我想学习一种干净的方法来有条件地渲染我的组件。

Ashwin 这里有几个问题。

  • 您的组件名称应以大写字母开头。
  • 使用数组代替 object obj。使用数组并循环遍历它们比循环 objects.
  • 更容易
  • 不要将整个组件包含在 if 语句中。这是不好的做法。
  • props == "All" 是错误的。道具是 object 而不是字符串。这是没有渲染的主要原因。该 if 语句将始终 return false。
  • <img> 不接受 children 所以不要将 {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 添加另一个节日,比如复活节,你只需要更改数组和传递的道具值。该组件不需要更改。