ReactJS prop 函数变得未定义

问题描述

我会很简短。标题完美地解释了主要问题,但我无法弄清楚这个“函数”在哪里变成或未定义。在阅读代码之前让我解释一下。\ App render Shows,Shows 渲染从'show'状态提取的多个Show。但是,如果您更改为 FAVS 选项卡,Shows Show 将从“favs”状态中提取
如果你想自己测试:https://github.com/Zackysh/bug-free-fortnight/tree/main

应用程序可让您在崩溃前查找节目并将其添加到收藏夹。当您再次转到 FAVS 选项卡并按收藏按钮时它会崩溃,它应该删除此收藏并更新节目,但它崩溃了。
首先,说明我想设置新值:

  const [shows,setShows] = useState([]) // this one receives a bunch of shows with unique id
  const [favs,setFavs] = useState([]) // this one will contain user fav shows
const [fav,setFav] = useState(false)

崩溃开始的 App.js 行:

return (
    <div className="application">
      // here 'fav' state change depends on which tab u visit (all shows / fav shows)
      <FullWidthTabs setFav={setFav} filter={filter} setFilter={setFilter} /> 
      <div id="mainBody" className="container text-center">
        <ul id="results">
        </ul>
      </div>
      <footer className="text-center">
        <Container>
          <Row>
            <Col>
              { // look here -------------------
                fav === true
                  ? <Shows addRemoveFav={addRemoveFav} fav={fav} shows={showFavs()} />
                  : <Shows addRemoveFav={addRemoveFav} fav={fav} shows={showShows()} />
              } // look here -------------------
            </Col>
          </Row>
        </Container>
      </footer>
    </div>
  )

好的,这里是 addRemoveFav 函数

  const addRemoveFav = (show) => {
    if (favs.length != 0) {
      const result = favs.filter(fav => show.show_id == fav.show_id)
      if (result.length < 1) {
        setFavs(favs.concat(show))
      } else {
        setFavs(favs.filter(fav => fav.show_id !== show.show_id))
      }
    } else {
      setFavs(favs.concat(show))
    }
  }

在此处显示

const Shows = ({ shows,addRemoveFav }) => {

    console.log('ADD REMOVE FAV JODER');
    console.log(addRemoveFav);

    const showList = () => shows.map(show => 
        <Show addRemoveFav={addRemoveFav} key={show.show_id} show={show} />
    )

    if (shows.length === 1) return <Show show={shows[0]} />
    if (shows.length < 10 && shows.length > 0) return <>{showList()}</>
    if (shows.length > 20) return <p>Too many matches,specify another filter</p>
    return <p>No matches</p>
}

显示组件,它更大所以只是相关的行;

const Show = ({ show,addRemoveFav }) => {
// ( .... )
return (
// ( .... )
<button
    type="button"
    className="btn btn-outline-success btn-floating"
    data-mdb-ripple-color="dark"
    onClick={() => addRemoveFav(show)} // here it sends current show object
/>

解决方法

有3个主要错误

1st. 错误 Cannot read property 'Component' of undefined 不是由任何变量、组件甚至反应代码引起的。它在您的 index.html 内。删除脚本行 <script src="https://npmcdn.com/react-log-state"></script> 修复了错误。将它移到 react 组件中,因为它需要 react 本身提供一些东西,并且在 react 之前执行它。

第二个。cannot appear as a descendant of <p>。它由 <Typography>{children}</Typography> 引起,在 function TabPanel(props) 中的 FullWidthTabs.js。您的 children 包含 div 和其他高级元素,但 Typography 返回 p。段落不应包含容器,而应包含简单的文本。

3rd. 在下面的卡片中,在您进行搜索后,在您单击星形图标后,发生崩溃的原因是您的 if (shows.length === 1) return <Show show={shows[0]} /> 中的此行 Show.js .只有当您只有 1 张卡时才会发生这种情况。这是因为当它只有 1(又名 addRemoveFav)时,您永远不会将值 Show 传递给组件 if === 1。只要它恰好是一张卡片,它就存在于 NetflixFavorite 页面中。修复它很简单:像这样传递 addRemoveFav 属性 if (shows.length === 1) return <Show show={shows[0]} addRemoveFav={addRemoveFav} />; 并解决您的问题。

当您有 2 张以上的卡片时,这不是问题的原因是因为有 1 张以上的卡片,您执行 showList 函数,该函数返回 <Show addRemoveFav={addRemoveFav} key={show.show_id} show={show} /> 的映射数组和 Show具有 addRemoveFav 属性的组件。

建议

一些改进代码的建议

1st. 渲染。你有这个

<Col>
  {
    fav === true
      ? <Shows addRemoveFav={onDelete} fav={fav} shows={showFavs()} />
      : <Shows addRemoveFav={onDelete} fav={fav} shows={showShows()} />
  }
</Col>

它打破了 DRY(不要重复自己)原则,因为代码本身会重复多次,只需要更改 - 提供给 shows 道具的数据。您可以通过以下方式轻松修复它:

<Col>
  <Shows
    addRemoveFav={onDelete}
    fav={fav}
    shows={fav ? showFavs() : showShows()}
  />
</Col>

想法还是一样的。但现在您不必重复两次代码。

第二个。您不需要执行 fav === true ? "" : ""。 JavaScript 在验证值方面非常出色。一个简单的 fav ? "" : "" 就可以做到。如果值(在本例中为 false)是 favnull、空字符串或 undefined,JavaScript 将返回 false。可能更多,不记得了。

这也适用于简单的 if 语句。此外,您甚至可以这样做{fav && <div>render me</div>}。如果最后必须是验证的结尾,则验证是某种反应子项,在这种情况下,div,它将返回该反应子项。支票可以随心所欲{((fav && try) || (!fav && number > 5)) && <div>render me with condition</div>}

第三。 拆分您的组件。注意到单个文件中有多个功能组件(主要是App)。它有点违反单一职责原则,因为文件负责多个内容。此外,文件变大,组件难以重复使用。只需为每个新的功能组件或类组件创建一个新文件。

第四。 回报更短。有时您会拥有一些函数,您知道这些函数将是一行代码来返回某些内容。例如这个:

const showFavs = () => {
  return favs.filter((show) =>
    JSON.stringify(show).toLowerCase().includes(filter.toLowerCase())
  );
};

你可以简单地做:

const showFavs = () =>
  favs.filter((show) =>
    JSON.stringify(show).toLowerCase().includes(filter.toLowerCase())
  );

这不是必需的。很多时候你会看到这样的函数带有 return 语句,因为有些人喜欢这样。很高兴知道您可以做到这一点。

第五。 Console.log()。为了安慰你不必只传入字符串或变量。实际上,您可以将字符串和数组、函数或其他任何内容组合到一行中。所以,而不是:

console.log("ADD REMOVE FAV JODER");
console.log(addRemoveFav);

console.log("ADD REMOVE FAV JODER",addRemoveFav);。测试时,您的控制台将减少垃圾邮件。也更容易导航。

6th. OnClick 就地执行功能。而不是创建一个新函数 const tryToFix = () => addRemoveFav(show); 只是为了将它传递给 onClick={tryToFix} 有点没用。你在里面没有做任何逻辑。这样你就可以在没有任何新函数onClick={() => addRemoveFav(show)}的情况下当场执行它。注意,如果您执行函数(如 function())而不只是传递引用(如 function),则必须使用箭头或简单的函数 () =>,因为它会在加载时执行,而不是在点击时执行。

7th. 让代码更漂亮!加载您的文件后,我的 IDE 对其进行了有趣的改造。如果您使用 VSC(react 会推荐它),请安装一个名为 Prettier 的扩展。适用于许多不同的语言,包括 react。如果你想改变一些东西,它是完全可定制的。安装后,您需要转到设置以启用它OnSave,因此每当您保存文件时,它都会重新格式化您的代码以使其更美观。

希望这些建议有所帮助。你可能知道一些,也可能不知道。了解这些基础知识总是好的。