【问题标题】:where to place componentDidMount in order to change link Navbar color while scrolling in React / Gatsby?在 React / Gatsby 中滚动时在哪里放置 componentDidMount 以更改链接导航栏颜色?
【发布时间】:2020-10-20 13:23:19
【问题描述】:

我的问题类似于this one,我知道我需要在导航栏链接中添加一个 id,并在 componentDidMount 上添加一个事件侦听器(使用 handleScroll 函数),这对我来说已经很清楚了。

我会事先道歉,因为我可能会问一些愚蠢的问题或我应该已经知道的问题。

问题是,即使我对 vanilla JS 有经验,但我对 react 和 gatsby 还是很陌生,所以我不确定将 componentDidMount 放在gatsby starter I am using 的确切位置。

这个启动器是一个单页应用程序,所有部分都加载在索引(主页)中。例如,其中一个部分名为 About,我想在其中添加 componentDidMount。我已将 about.tsx 文件隐藏到 components 目录,但我不确定将 componentDidMount 放在哪里。

about.tsx 内容:

/** @jsx jsx */
import { jsx } from "theme-ui"
import Divider from "../elements/divider"
import Inner from "../elements/inner"
import Content from "../elements/content"
import SVG from "./svg"
import { UpDown, UpDownWide } from "../styles/animations"
// @ts-ignore
import AboutMDX from "../sections/about"


const About = ({ offset, factor = .99 }: { offset: number; factor?: number }) => (
  <div>
    <Divider
      bg="divider"
      clipPath="polygon(0 16%, 100% 4%, 100% 82%, 0 94%)"
      speed={0.2}
      offset={offset}
      factor={factor}
    />
    <Divider speed={0.1} offset={offset} factor={factor}>
      <UpDown>
        <SVG icon="box" hiddenMobile width={6} color="icon_blue" left="50%" top="75%" />
        <SVG icon="upDown" hiddenMobile width={8} color="icon_darkest" left="70%" top="20%" />
        <SVG icon="triangle" width={8} stroke color="icon_darkest" left="25%" top="5%" />
        <SVG icon="upDown" hiddenMobile width={24} color="icon_orange" left="80%" top="80%" />
      </UpDown>
      <UpDownWide>
        <SVG icon="arrowUp" hiddenMobile width={16} color="icon_purple" left="5%" top="80%" />
        <SVG icon="triangle" width={12} stroke color="icon_brightest" left="95%" top="50%" />
        <SVG icon="circle" hiddenMobile width={6} color="icon_brightest" left="85%" top="15%" />
        <SVG icon="upDown" hiddenMobile width={8} color="icon_darkest" left="45%" top="10%" />
      </UpDownWide>
      <SVG icon="circle" hiddenMobile width={6} color="icon_brightest" left="4%" top="20%" />
      <SVG icon="circle" width={12} color="icon_darkest" left="70%" top="60%" />
      <SVG icon="box" width={6} color="icon_orange" left="10%" top="10%" />
      <SVG icon="box" width={12} color="icon_darkest" left="20%" top="30%" />
      <SVG icon="hexa" width={8} stroke color="icon_darkest" left="80%" top="70%" />
    </Divider>
    <Content speed={0.4} offset={offset} factor={factor}>
      <Inner>
        <AboutMDX/>
      </Inner>
    </Content>
  </div>
)

export default About

如果有人能指出我如何将 componentDidMount 添加到此 about 部分,我将不胜感激?提前致谢。

编辑:据我所知,这是一个无状态功能组件(对吗?),因此不支持生命周期方法。但我不知道如何将此组件转换为有状态组件或如何将其包装在有状态容器中。

【问题讨论】:

  • 功能组件可以使用状态并使用 Hooks 管理更改效果。 reactjs.org/docs/hooks-intro.html
  • 现在我很困惑,我认为功能组件(又名无状态组件)不支持状态和效果。并且认为类组件(又名有状态组件)确实如此。无论如何,我不知道如何将这个无状态组件转换为有状态组件,所以我可以使用 componentDidMount。
  • 他们引入 Hooks 是因为它改善了开发人员的体验,而且函数组件通常比基于类/原型的组件性能更好。

标签: reactjs gatsby


【解决方案1】:

您有一个功能组件,其中不处理纯 state 您可能知道(您不需要构造函数等。我将在答案末尾添加一些文档)。由于 React 钩子,您拥有完全相同的功能。

在您的情况下,由于前面提到的原因,您将无法拥有componentDidMount() 本身,但是,您拥有一个添加完全相同功能的useEffect 挂钩。

const About = ({ offset, factor = .99 }: { offset: number; factor?: number }) => {
 
  useEffect(() => {
    // your function that handles the scroll
  },[]);

  return <div>
    <Divider
      bg="divider"
      clipPath="polygon(0 16%, 100% 4%, 100% 82%, 0 94%)"
      speed={0.2}
      offset={offset}
      factor={factor}
    />
    <Divider speed={0.1} offset={offset} factor={factor}>
      <UpDown>
        <SVG icon="box" hiddenMobile width={6} color="icon_blue" left="50%" top="75%" />
        <SVG icon="upDown" hiddenMobile width={8} color="icon_darkest" left="70%" top="20%" />
        <SVG icon="triangle" width={8} stroke color="icon_darkest" left="25%" top="5%" />
        <SVG icon="upDown" hiddenMobile width={24} color="icon_orange" left="80%" top="80%" />
      </UpDown>
      <UpDownWide>
        <SVG icon="arrowUp" hiddenMobile width={16} color="icon_purple" left="5%" top="80%" />
        <SVG icon="triangle" width={12} stroke color="icon_brightest" left="95%" top="50%" />
        <SVG icon="circle" hiddenMobile width={6} color="icon_brightest" left="85%" top="15%" />
        <SVG icon="upDown" hiddenMobile width={8} color="icon_darkest" left="45%" top="10%" />
      </UpDownWide>
      <SVG icon="circle" hiddenMobile width={6} color="icon_brightest" left="4%" top="20%" />
      <SVG icon="circle" width={12} color="icon_darkest" left="70%" top="60%" />
      <SVG icon="box" width={6} color="icon_orange" left="10%" top="10%" />
      <SVG icon="box" width={12} color="icon_darkest" left="20%" top="30%" />
      <SVG icon="hexa" width={8} stroke color="icon_darkest" left="80%" top="70%" />
    </Divider>
    <Content speed={0.4} offset={offset} factor={factor}>
      <Inner>
        <AboutMDX/>
      </Inner>
    </Content>
  </div>
}

export default About

useEffect,基本上是componentDidMountcomponentDidUpdatecomponentWillUnmount的组合。如您所见,它接受一个数组作为参数,称为 deps(依赖项)。这意味着您可以在那里传递一个变量(或变量数组,如props)来触发效果(useEffect)函数。如果您传递一个空数组,它将表现为componentDidMount,一旦加载了 DOM 树就会触发该函数。

请记住,在 Gatsby 中处理滚动可能会很棘手,因为 gatsby develop 呈现在浏览器端(其中有一个 window 对象),但 gatsby build 出现在服务器端(节点端),出于显而易见的原因there's no window or document。您可能需要添加一个条件来绕过它:

  useEffect(() => {
    if(typeof window !== 'undefined'){
       // your function that handles the scroll
    }
  },[]);

我会推荐一些读物:

【讨论】:

  • 谢谢 Ferran,我正在尝试使用您的建议,但我认为其中缺少括号,对吗?我得到了“)”的预期。如果我确实添加了缺失的 ),我会收到此错误:> 25 |返回
    | ^
  • 对我来说看起来不错。语句末尾有一个大括号,而不是 )
  • Ferran,您的答案是正确的并且有效。你是对的,我错过了大括号。我不确定在这里做什么,因为乌萨马的回答也是正确的。由于我缺乏声誉,我无法支持您的回答:( Oussama 回答了标题“在哪里放置 componentDidMount”的问题,但您的回答告诉我,我不需要使用 componentDidMount。不知道在这里做什么。
  • 你从一个功能组件开始,我的回答主要是教你为什么错了,该怎么做,怎么做,提供和搜索我认为你可能会觉得有用的文章,使用您的起始用例(此外我回答得更快,呵呵)。我不能谈论其他答案,但它会更改您的组件(到类组件)以添加componentDidMount。显然,选择是你的,这取决于你。功能组件比基于类的组件具有更好的性能。尽管有赞成票,但我总是很乐意提供帮助。
【解决方案2】:

Gatsby 应用仍然是 React 应用,因此您在 React 中学到的所有内容在 Gatsby 中仍然可用。
很多人认为 Gatsby 只是用于创建页面网站,但它的功能远不止于此。
对于您的问题,sn-p 值得一千字,所以这是您的解决方案:

/** @jsx jsx */
import React, {Component} from "react"
import { jsx } from "theme-ui"
import Divider from "../elements/divider"
import Inner from "../elements/inner"
import Content from "../elements/content"
import SVG from "./svg"
import { UpDown, UpDownWide } from "../styles/animations"
// @ts-ignore
import AboutMDX from "../sections/about"


type AboutProps = { offset: number; factor?: number }
export default class About extends Component <AboutProps, {}> {
  
  componentDidMoun(){
    // do whatever you want here
  }
  render(){
    const { offset, factor = .99 } = this.props;
    return(
      <div>
        <Divider
          bg="divider"
          clipPath="polygon(0 16%, 100% 4%, 100% 82%, 0 94%)"
          speed={0.2}
          offset={offset}
          factor={factor}
        />
        <Divider speed={0.1} offset={offset} factor={factor}>
          <UpDown>
            <SVG icon="box" hiddenMobile width={6} color="icon_blue" left="50%" top="75%" />
            <SVG icon="upDown" hiddenMobile width={8} color="icon_darkest" left="70%" top="20%" />
            <SVG icon="triangle" width={8} stroke color="icon_darkest" left="25%" top="5%" />
            <SVG icon="upDown" hiddenMobile width={24} color="icon_orange" left="80%" top="80%" />
          </UpDown>
          <UpDownWide>
            <SVG icon="arrowUp" hiddenMobile width={16} color="icon_purple" left="5%" top="80%" />
            <SVG icon="triangle" width={12} stroke color="icon_brightest" left="95%" top="50%" />
            <SVG icon="circle" hiddenMobile width={6} color="icon_brightest" left="85%" top="15%" />
            <SVG icon="upDown" hiddenMobile width={8} color="icon_darkest" left="45%" top="10%" />
          </UpDownWide>
          <SVG icon="circle" hiddenMobile width={6} color="icon_brightest" left="4%" top="20%" />
          <SVG icon="circle" width={12} color="icon_darkest" left="70%" top="60%" />
          <SVG icon="box" width={6} color="icon_orange" left="10%" top="10%" />
          <SVG icon="box" width={12} color="icon_darkest" left="20%" top="30%" />
          <SVG icon="hexa" width={8} stroke color="icon_darkest" left="80%" top="70%" />
        </Divider>
        <Content speed={0.4} offset={offset} factor={factor}>
          <Inner>
            <AboutMDX/>
          </Inner>
        </Content>
      </div>
      )
  }
}

【讨论】:

  • 这个答案也应该被接受,因为它回答了标题中的问题。 Oussama 我感谢您的时间并教我如何转换组件,非常感谢您,我接受了另一个答案,但因为 Ferran 首先回答能够向我展示为什么我不需要转换组件以及为什么。您的答案仍然正确,也应该被接受。不幸的是,我没有足够的声誉来支持您的回答,我深表歉意,并再次感谢您的回答和您的时间。
猜你喜欢
相关资源
最近更新 更多
热门标签