切换到功能组件的问题会与useEffect发生反应

时间:2020-04-17 15:08:00

标签: javascript html reactjs d3.js

我目前正在尝试将类组件(正在工作)更改为功能组件(无法工作)。基本上,我的目标是使元素在页面上居中。

编辑:如果任何人都可以评论ref={tc=>(this.treeContainer=tc)}的行为,那将也非常有帮助!

我的班级组件(有效):

/** 
 * Component returning a div containing a tree
 * Need to declare as class for ComponentDidMount() 
 */
class CenterMe extends React.PureComponent {

    state={}

    /* Used to center the tree on render */
    componentDidMount() {
      const dimensions = this.treeContainer.getBoundingClientRect();
      this.setState({
        translate: {
          x: 30,
          y: dimensions.height / 2
        }
      });
    }

    /* Returns the actual tree content */
    render(){
      return(
          <div class="treeWrapper" ref={tc => (this.treeContainer = tc)}>
              <Tree
                  translate = {this.state.translate}
              />
          </div>
      );
    }
}

我当前的功能组件如下所示,并且不起作用:

function CenterMe() {
    const [state, setState] = useState({translate:{x:0,y:0}); // Added thanks to @jstu

    /* Used to center the tree on render */
    useEffect(()=> {
      const dimensions = treeContainer.getBoundingClientRect();
      setState({
        translate: {
          x: 30,
          y: dimensions.height / 2
        }
      });
    });

    /* Returns the actual tree content */
      return(
          <div class="treeWrapper" ref={tc => (this.treeContainer = tc)}>
              <Tree
                  translate = {this.state.translate}
              />
          </div>
      );
}

更具体地说,它抱怨未定义setState和treeContainer。 如果重要的话,Tree组件是从react-d3-tree导入的,translate函数基本上按照它所说的进行操作-它移动了树。 我认为问题主要集中在ref={tc=>(this.treeContainer=tc)}上,因此对此的解释也可能会有所帮助。非常感谢!

3 个答案:

答案 0 :(得分:2)

您需要使用添加两个钩子useRefuseState来进行转换

function CenterMe() {
 const [translate, setTranslate] = useState({ x: 0, y: 0 });
 const treeContainer = useRef(null)

 /* Used to center the tree on render */
 useEffect(()=> {
  const dimensions = treeContainer.current.getBoundingClientRect();
  setTranslate({
      x: 30,
      y: dimensions.height / 2
  });
 }, []);

/* Returns the actual tree content */
  return(
      <div class="treeWrapper" ref={treeContainer}>
          <Tree
              translate={translate}
          />
      </div>
  );
}

useState将替换基于类的组件中的setState,如果您访问treeContainer.current键,useRef将为您提供当前引用。

要解释什么是ref部分,基本上,您的情况下的ref是引用dom节点,例如,如果您的树组件看起来像这样:

<div className="awesome-class">
 <p>Hi</p>
</div>

这里的use ref所做的是,它将为您提供dom元素ref,假设树的组件与上面的示例类似,它将看起来像这样。

    <div class="treeWrapper">
     <div className="awesome-class">
      <p>Hi</p>
     </div>
    </div>

使用ref可以从dom中获取元素,例如,在您的特定情况下getBoundingClientRect将为您提供该特定元素的大小,如您所见,这非常有用,因为您能够使用父级组件中的子级值。在此处使用挂钩的更多信息:https://reactjs.org/docs/hooks-reference.html#useref

答案 1 :(得分:1)

所以您似乎错过了状态挂钩。试试这个

    function CenterMe() {
    const [state, setState] = useState({translate:{x:0,y:0}}); // Set an initial state
    const treeContainer = useRef(null);

        /* Used to center the tree on render */
        useEffect(()=> {
          const dimensions = treeContainer.current.getBoundingClientRect();
          setState({
            translate: {
              x: 30,
              y: dimensions.height / 2
            }
          });
        },[]);

        /* Returns the actual tree content */
          return(
              <div class="treeWrapper" ref={treeContainer}>
                  <Tree
                      translate = {state.translate}
                  />
              </div>
          );
    }

我还没有测试过。但是您缺少的是useState挂钩。 还只是注意到您的意思是要实现componentDidMount。因此您需要在最后传递一个空数组。使其表现为componentDidMount

答案 2 :(得分:1)

好,有几件事。 使用状态返回可以用语法[]解构的数组。像这样

    const [someName, setSomeName] = useState({
        translateX: 10,
        translateY: 20 
    })

您正在给useState一个匿名函数。我不知道您是否可以做到,以前从未做到过。

但是尝试我上面写的解决方案。通过调用该方法来设置translatioY的值,然后在Tree组件中执行此操作。

<Tree  translate = {someName}/>

对于ref,您必须使用useRef()钩子