programing

이 React Class 구성 요소를 후크로 작성하는 더 좋은 방법?

prostudy 2022. 4. 3. 19:49
반응형

이 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

흐름을 설명하는 가장 좋은 방법:

  1. 구성 요소가 장착되면 깃발은 거짓이고 우리는 div에 대한 참조가 없기 때문에StyledHeightContainer그것을 제공하려고 할 것이고 따라서 그것에 대한 참고자료를 제공할 것이다.

  2. componentDidMount-> 오버플로 플래그를 설정해 보십시오(현재 렌더링이 아직 완료되지 않아 참조가 무효가 됨).그러나 플래그를 설정함으로써 렌더 패스를 추가로 대기열에 넣는다.

  3. 1차 초기 렌더링 완료 -> 지금 Div에 대한 참조가 있다.

  4. 두 번째(대기열) 렌더가 발생하여componentDidUpdate-> 내용물이 넘칠 때 오버플로를 계산하여 깃발을 true로 설정할 수 있다.

  5. 사용자가 버튼을 클릭할 때 -> 플래그를 false로 설정하면 리렌더가 트리거되어StyledHeightContainerDOM에서 제거될 것이다.

후크가 있는 기능 구성 요소

코드 샌드박스

후크를 사용하여 이것을 기능적 구성요소로 다시 작성했을 때, 나는 결국 다음과 같이 되었다.

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)를 추가해야 한다는 것에 놀랐다. 이것이 내가 두 번째 렌더링을 강제로 발생시키는 방법이다(즉,에 상당하는componentDidUpdateclass 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레이아웃 후에 업데이트하기를 원하는 경우.

참조URL: https://stackoverflow.com/questions/61149158/a-better-way-to-write-this-react-class-component-with-hooks

반응형