首页 > 解决方案 > 在功能组件上设置 ref

问题描述

我正在尝试将这个基于类的反应组件更改为功能组件,但我在设置引用时遇到了一个无限循环问题,我认为这是因为在每次渲染时,引用都是一个新对象。

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

index-class.js -参考

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>
    );
}
}

到目前为止我所尝试的。

索引功能.js

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>
  );
};

usePrevious.js -链接

import { useRef, useEffect } from "react";

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

export { usePrevious };

标签: reactjs

解决方案


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

通过在功能组件上设置引用的方式如下:

const Component = () => {
   const ref = useRef(null)

   return (
      <div ref={ref} />
   )
}

更多信息可以在这里找到:https ://reactjs.org/docs/refs-and-the-dom.html


推荐阅读