이 React Class 구성 요소를 후크로 작성하는 더 좋은 방법?
나는 높이가 고정된 구간을 가지고 있다.들어오는 콘텐츠가 맞는지 안 맞는지 컴포넌트가 언제 장착(첫 렌더링)맞지 않으면 '추가 읽기' 버튼을 렌더링해야 한다.
다음과 같이 보인다.
원래 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
흐름을 설명하는 가장 좋은 방법:
구성 요소가 장착되면 깃발은 거짓이고 우리는 div에 대한 참조가 없기 때문에
StyledHeightContainer
그것을 제공하려고 할 것이고 따라서 그것에 대한 참고자료를 제공할 것이다.인
componentDidMount
-> 오버플로 플래그를 설정해 보십시오(현재 렌더링이 아직 완료되지 않아 참조가 무효가 됨).그러나 플래그를 설정함으로써 렌더 패스를 추가로 대기열에 넣는다.1차 초기 렌더링 완료 -> 지금 Div에 대한 참조가 있다.
두 번째(대기열) 렌더가 발생하여
componentDidUpdate
-> 내용물이 넘칠 때 오버플로를 계산하여 깃발을 true로 설정할 수 있다.사용자가 버튼을 클릭할 때 -> 플래그를 false로 설정하면 리렌더가 트리거되어
StyledHeightContainer
DOM에서 제거될 것이다.
후크가 있는 기능 구성 요소
후크를 사용하여 이것을 기능적 구성요소로 다시 작성했을 때, 나는 결국 다음과 같이 되었다.
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
class solution에서.
이것이 맞는지 아니면 누군가가 두 번째 해결책을 더 간결하게 쓸 수 있는지 알 수 있는가?
참고
내가 묻는 이유 중 하나는 콘솔에서 다음과 같은 경고를 받기 때문이다.
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/TerminalList.js
우선, 나는 생각하고 있었다.
useEffect(() => {
setOverflowActive(isOverflowing(wrapper.current));
}, [wrapper]);
그러나 이렇게 하면 useEffect를 다시 호출하여 Read more(추가 읽기) 버튼을 클릭하게 된다.왜냐하면 그것은 그것의 가치가 아니라 포장지의 참조를 비교하고 있었기 때문이다.
따라서 참조 비교를 피하려면 콜백 후크를 사용해야 한다.
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를 참조하십시오.
질문 고마워 :)
너는 여분의 것을 추가할 수 있다.useEffect(() => (...),[])
그런 식으로 행동하는componentDidMount()
그리고 또.useEffect(() => (...))
그런 식으로 행동하는componentDidUpdate()
. 그러면 당신은 제거할 수 있어야 한다.userClicked
.
이것은 생활방식이 어떻게 갈고리와 함께 작용하는지를 보여주는 좋은 연결고리다.https://dev.to/trentyang/replace-lifecycle-with-hooks-in-react-3d4n
useEffect(() => {
setOverflowActive(isOverflowing(wrapper.current));
}, []);
useEffect(() => {
if (!overflowActive && wrapper.current) {
setOverflowActive(isOverflowing(wrapper.current))
}
});
두 번째가 필요할 수도 있다.useLayoutEffect
레이아웃 후에 업데이트하기를 원하는 경우.
'programing' 카테고리의 다른 글
파이톤 대본에 #!(쉐뱅)을 넣어야 하나, 어떤 형식을 취해야 하나? (0) | 2022.04.03 |
---|---|
렌더 프로펠러 내부에 리액션 후크 사용 (0) | 2022.04.03 |
리액터 힘 쿼리 문자열이 단일 요소가 있는 배열이어야 함 (0) | 2022.04.03 |
첫 번째 앱 로드 시 네이티브 헤더/하단 탭바 점프 반응 (0) | 2022.04.03 |
Vuetify 버튼의 텍스트 색상을 변경하는 방법 (0) | 2022.04.03 |