gpt4 book ai didi

javascript - 用 Hooks 编写这个 React 类组件的更好方法是什么?

转载 作者:行者123 更新时间:2023-12-03 14:22:11 25 4
gpt4 key购买 nike

我有一个具有固定高度的部分。我不知道组件何时安装(首次渲染)是否适合传入的内容。如果它不适合,那么我需要渲染一个“阅读更多”按钮。

它看起来像这样: enter image description here

我最初使用生命周期方法 DidMount/DidUpdate 将其编写为类组件:

类组件

import React, { createRef } from "react"
import styled from "@emotion/styled"

import Section from "../Section"
import ButtonReadMore from "./ButtonReadMore"
import Paragraphs from "./Paragraphs"

const StyledHeightContainer = styled.div`
max-height: 150px;
overflow: hidden;
`

class ParagraphList extends React.Component {
state = {
overflowActive: false,
}
wrapper = createRef() // so we can get a ref to the height container

isOverflowing(el) {
if (el) return el.offsetHeight < el.scrollHeight
}

componentDidMount() {
this.setState({ overflowActive: this.isOverflowing(this.wrapper.current) })
}

componentDidUpdate() {
if (this.wrapper.current && !this.state.overflowActive) {
this.setState({
overflowActive: this.isOverflowing(this.wrapper.current),
})
}
}

handleClick() {
this.setState({ overflowActive: false })
}

render() {
const { moreButtonText, titleText, paragraphs, theme } = this.props

return (
<>
<Section overflowActive={this.state.overflowActive}>
{this.state.overflowActive || !this.wrapper.current ? (
<StyledHeightContainer ref={this.wrapper}>
<Paragraphs paragraphs={paragraphs} />
</StyledHeightContainer>
) : (
<Paragraphs paragraphs={paragraphs} />
)}
</Section>
{overflowActive ?
<ButtonReadMore
onClicked={handleClick.bind(this)}
moreButtonText={moreButtonText}
theme={theme}
/>
: null}
</>
)
}
}

export default ParagraphList

我解释流程的最佳方式:

  1. 当组件安装时,标志为 false,并且我们没有引用 div,因此 StyledHeightContainer将尝试渲染并提供对其的引用

  2. componentDidMount -> 尝试设置溢出标志(该标志将为 false,因为此时我们尚未完成渲染,因此 ref 将为 null)。但无论如何设置该标志,我们都会对额外的渲染 channel 进行排队

  3. 第一次初始渲染完成 -> 我们现在有了对 div 的引用

  4. 发生第二次(排队)渲染,触发 componentDidUpdate -> 我们可以计算溢出并在内容溢出时将标志设置为true

  5. 当用户单击按钮时 -> 将标志设置为 false,这将触发重新渲染,因此 StyledHeightContainer将从 DOM 中删除。

带钩子(Hook)的功能组件

Sandbox of the code

当我使用 Hooks 将其重新编写为功能组件时,我得到了这样的结果:

import React, { createRef, useEffect, useState } from "react"
import styled from "@emotion/styled"

import Section from "../Section"
import ButtonReadMore from "./ButtonReadMore"
import Paragraphs from "./Paragraphs"

const StyledHeightContainer = styled.div`
max-height: 150px;
overflow: hidden;
`

const ParagraphList = ({ moreButtonText, titleText, paragraphs, theme }) => {
const [overflowActive, setOverflowActive] = useState(false)
const [userClicked, setUserClicked] = useState(false)
const wrapper = createRef(false) // so we can get a ref to the height container

const isOverflowing = el => {
if (el) return el.offsetHeight < el.scrollHeight
}

useEffect(() => {
if (!userClicked && !overflowActive && wrapper.current) {
setOverflowActive(isOverflowing(wrapper.current))
}
}, [userClicked]) // note: we only care about state change if user clicks 'Read More' button

const handleClick = () => {
setOverflowActive(false)
setUserClicked(true)
}

return (
<>
<Section theme={theme} overflowActive={overflowActive}>
{!userClicked && (overflowActive || !wrapper.current) ? (
<StyledHeightContainer ref={wrapper}>
<Paragraphs paragraphs={paragraphs} />
</StyledHeightContainer>
) : (
<Paragraphs paragraphs={paragraphs} />
)}
</Section>
{overflowActive ?
<ButtonReadMore
onClicked={handleClick.bind(null)}
moreButtonText={moreButtonText}
theme={theme}
/>
: null}
</>
)
}

export default ParagraphList

令我惊讶的是,我需要添加另一个状态 (userClicked),这就是我强制进行第二次渲染的方式(即相当于类解决方案中的 componentDidUpdate)。

这是正确的还是有人可以看到更简洁的方法来编写第二个解决方案?

注意

我问的原因之一是因为在控制台中我收到此警告:

48:6  warning  React Hook useEffect has missing dependencies:
'overflowActive' and 'wrapper'. Either include them or remove the
dependency array react-hooks/exhaustive-deps

而且我不认为我想将它们添加到依赖项数组中,因为我不想在它们更改时触发渲染...?

最佳答案

我非常享受解决查询的过程。

这是实现:https://codesandbox.io/s/react-using-hooks-in-section-component-5gibi?file=/src/ParagraphList.js

首先,我想到的是

useEffect(() => {
setOverflowActive(isOverflowing(wrapper.current));
}, [wrapper]);

但是如果我们这样做,当我们单击“阅读更多”按钮时,它将再次调用 useEffect。因为它是比较包装器的引用而不是它的值。

因此,为了避免引用比较,我们必须使用 useCallback Hook 。

 const isOverflowingNode = node => {
return node.offsetHeight < node.scrollHeight;
};

const wrapper = useCallback(node => {
if (node !== null) {
setOverflowActive(isOverflowingNode(node));
}
}, []);

我遇到了精彩的讨论:https://github.com/facebook/react/issues/14387

欲了解更多信息: https://reactjs.org/docs/hooks-faq.html#how-can-i-measure-a-dom-node

谢谢你的提问:)

关于javascript - 用 Hooks 编写这个 React 类组件的更好方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61149158/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com