Reactjs 在功能组件上设置ref

Reactjs 在功能组件上设置ref,reactjs,Reactjs,我试图将这个基于类的react组件更改为函数组件,但在设置引用时遇到了一个无限循环问题,我认为这是因为在每次渲染时,ref都是一个新对象 如何将基于类的组件转换为功能组件 index-class.js- 这里的问题是通过setState和useffect(这就是导致无限循环的原因)将引用设置为更新 在功能组件上设置引用的方法如下: const组件=()=>{ const ref=useRef(空) 返回( ) } 更多信息可以在这里找到:那么我应该如何在我的功能组件中重写它,使其像上面所示的类

我试图将这个基于类的react组件更改为函数组件,但在设置引用时遇到了一个无限循环问题,我认为这是因为在每次渲染时,ref都是一个新对象

如何将基于类的组件转换为功能组件

index-class.js-


这里的问题是通过setState和useffect(这就是导致无限循环的原因)将引用设置为更新

在功能组件上设置引用的方法如下:

const组件=()=>{
const ref=useRef(空)
返回(
)
}

更多信息可以在这里找到:

那么我应该如何在我的功能组件中重写它,使其像上面所示的类组件一样工作-像您那样转换组件,复制我共享的代码,并从
setState
中删除ref,此外,您还可以删除
setInnerRef
函数,因为该函数将不再使用。如果您想获取高度状态的上一个值,而不是使用
usePrevious
函数,您可以在需要设置新状态时随时访问该函数:
setState((prevState)=>console.log(“prevState”)
,谢谢@ale,我没有得到错误,但我没有得到平滑过渡效果,它没有在点击时切换回来,我在这里错过了什么?但是在基于类的组件中,它的工作不用担心!当您需要访问引用的元素时,它无法正常工作,您需要使用
ref.current
来访问它,而不仅仅是
ref
。另外,还有一个错误,您忘记将状态从类(在其中使用this.state)更新为函数组件(在其中只调用setState函数)。工作沙箱:
class Collapse extends React.Component {
constructor(props) {
    super(props);
    this.state = {
        showContent: false,
        height: "0px",
        myRef: null,
    };
}

componentDidUpdate = (prevProps, prevState) => {
    if (prevState.height === "auto" && this.state.height !== "auto") {
        setTimeout(() => this.setState({ height: "0px" }), 1);
    }
}

setInnerRef = (ref) => this.setState({ myRef: ref });

toggleOpenClose = () => this.setState({
    showContent: !this.state.showContent,
    height: this.state.myRef.scrollHeight,
});

updateAfterTransition = () => {
    if (this.state.showContent) {
        this.setState({ height: "auto" });
    }
};

render() {
    const { title, children } = this.props;
    return (
        <div>
            <h2 onClick={() => this.toggleOpenClose()}>
                Example
            </h2>
            <div
                ref={this.setInnerRef}
                onTransitionEnd={() => this.updateAfterTransition()}
                style={{
                    height: this.state.height,
                    overflow: "hidden",
                    transition: "height 250ms linear 0s",
                }}
            >
                {children}
            </div>
        </div>
    );
}
}
import React, { useEffect, useState } from "react";
import { usePrevious } from "./usePrevious";

const Collapse = (props) => {
  const { title, children } = props || {};

  const [state, setState] = useState({
    showContent: false,
    height: "0px",
    myRef: null
  });

  const previousHeight = usePrevious(state.height);

  useEffect(() => {
    if (previousHeight === "auto" && state.height !== "auto") {
      setTimeout(
        () => setState((prevState) => ({ ...prevState, height: "0px" })),
        1
      );
    }
  }, [previousHeight, state.height]);

  const setInnerRef = (ref) =>
    setState((prevState) => ({ ...prevState, myRef: ref }));

  const toggleOpenClose = () =>
    setState((prevState) => ({
      ...prevState,
      showContent: !state.showContent,
      height: state.myRef.scrollHeight
    }));

  const updateAfterTransition = () => {
    if (state.showContent) {
      this.setState((prevState) => ({ ...prevState, height: "auto" }));
    }
  };

  return (
    <div>
      <h2 onClick={toggleOpenClose}>{title}</h2>
      <div
        ref={setInnerRef}
        onTransitionEnd={updateAfterTransition}
        style={{
          height: state.height,
          overflow: "hidden",
          transition: "height 250ms linear 0s"
        }}
      >
        {children}
      </div>
    </div>
  );
};
import { useRef, useEffect } from "react";

function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  }, [value]);
  return ref.current;
}

export { usePrevious };