ReactJS prop 函数变得未定义

ReactJS prop function becomes undefined

我会简短的。标题完美地解释了主要问题,但我无法弄清楚这个 'function' 在哪里变成或未定义。在阅读代码之前让我解释一下。\ App render Shows,Shows render multiple Show extracted from 'show' state。但是如果你切换到 FAVS 选项卡,Shows Show 将从 'favs' 状态中提取出来。
如果你想自己测试一下:https://github.com/Zackysh/bug-free-fortnight/tree/main

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

  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 之前执行它。

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

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

当你有 2 张以上的卡片时,这不是问题的原因是,当卡片超过 1 张时,你执行 showList 函数,return 是 <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 prop 的数据。您可以使用以下方法轻松修复它:

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

思路还是一样。但现在您不必重复两次代码。

2nd. 你不需要做fav === true ? "" : ""。 JavaScript 在验证值方面非常棒。一个简单的 fav ? "" : "" 就可以做到。 JavaScript 将 return false 如果值,在这种情况下,favnullundefined、空字符串或 false.可能更多,不记得了。

这也适用于简单的 if 语句。此外,你甚至可以这样做{fav && <div>render me</div>}。如果在最后,必须是最后,验证是某种反应子,在这种情况下,div,它将 return 反应子。支票可以像您希望的那样复杂{((fav && try) || (!fav && number > 5)) && <div>render me with condition</div>}

3rd. 拆分组件。注意到单个文件中有多个功能组件(主要是App)。它有点违反单一职责原则,因为文件负责多个内容。此外,文件变大,组件难以复用。只需为每个新功能或 class、component.

创建一个新文件

第 4. 更短 return 秒。有时你会拥有你知道的功能,这些功能将是 return 某物的单行代码。例如:

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 语句,因为有些人更喜欢这样。很高兴知道你能做到这一点。

5.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 的扩展。使用许多不同的语言,包括反应。如果你想改变一些东西,它是完全可定制的。安装后,您需要转到设置以启用它OnSave,因此每当您保存文件时,它都会重新格式化您的代码以使其更漂亮。

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