【问题标题】:findDOMNode is deprecated in StrictMode how to use refs instead在 StrictMode 中不推荐使用 findDOMNode 如何改用 refs
【发布时间】:2020-12-19 23:44:13
【问题描述】:

大家好,我只是想在路由器转换期间使用 Refs 来定位组件中的元素。目前,来自 React Transition Group 的 onEnter、onExit 和 addEndListener 事件已经让您可以访问正在制作动画的 DOM 节点。有一段时间没问题,但现在你可能已经知道你得到了错误。

index.js:1 警告:在 StrictMode 中不推荐使用 findDOMNode。 findDOMNode 被传递了一个在 StrictMode 中的 Transition 实例。相反,直接将 ref 添加到要引用的元素。详细了解如何安全使用 refs [1]

这是我的 App.js 代码

    import React from 'react';
    import { BrowserRouter as Router, Route } from 'react-router-dom';
    import { CSSTransition } from 'react-transition-group';
    import { gsap } from 'gsap';
  

    import Header from './tools/header';
    import About from './pages/about';
    import Home from './pages/home';

    const routes = [
        { path: '/', name: 'Home', Component: Home },
        { path: '/about', name: 'About', Component: About },

    ]

    function Routeapp() {

        const nodeRef = React.useRef(null);

        const onEnter = (node) => {
            console.log(node)

            gsap.from(
                [node.children[0].firstElementChild, node.children[0].lastElementChild],
                {
                    duration: 0.6,
                    y: 30,
                    delay: 0.6,
                    ease: 'power3.inOut',
                    opacity: 0,
                    stagger: {
                        amount: 0.3,
                    },
                }
            );

        };

        const onExit = node => {
            gsap.to(
                [node.children[0].firstElementChild, node.children[0].lastElementChild],
                {
                    duration: 0.6,
                    y: -30,
                    ease: 'power3.inOut',
                    opacity: 0,
                    stagger: {
                        amount: 0.15,
                    },
                }
            );
        };

      return (
        <Router>
          <Header />
          <div className="container">
              {routes.map(({ path, Component }) => (
                  <Route key={path} exact path={path}>
                      {({ match }) => (
                          <CSSTransition
                              in={match != null}
                              key={path}
                              timeout={1200}
                              classNames="page"
                              onEnter={onEnter}
                              onExit={onExit}
                              unmountOnExit={true}

                          >
                              <div className="page" ref={nodeRef} >
                                  <Component />
                              </div>
                          </CSSTransition>
                      )}
                  </Route>
              ))}
          </div>
        </Router>
      );
    }
    export default Routeapp;

Home.js

import React from 'react';
import Title from '../tools/title';

const Home = () => {
  return (

          <div className="inner">
              <Title lineContent="this is the" lineContent2="Home page" />
              <div className={'infoBox'}>
                  <p className="info">hello mel and welcome</p>
              </div>
          </div>
  );
};

export default Home;

关于.js

import React from 'react';
import Title from '../tools/title';

const About = () => {
  return (

        <div className="inner">
          <Title lineContent={'this is the'} lineContent2={'About page'} />
          <div className={'infoBox'}>
            <p className="info pink">
              Lorem Ipsum is simply dummy text of the printing and typesetting
              industry. Lorem Ipsum has been the industry's standard dummy text ever
              since the 1500s, when an unknown printer took a galley of type and
              scrambled it to make a type specimen book. It has survived not only
              five centuries, but also the leap into electronic typesetting,
              remaining essentially unchanged. It was popularised in the 1960s with
              the release of Letraset sheets containing Lorem Ipsum passages, and
              more recently with desktop publishing software like Aldus PageMaker
              including versions of Lorem Ipsum.
            </p>
          </div>
        </div>
  );
};

export default About;

我的问题是我正在尝试找到一种方法来“引用”我的“Home”和“About”组件,这样我不仅可以为它们设置动画,还可以为“onExit”和“onEnter”道具添加不同的补间,如果可能。

我已尝试通过在 app.js 中尝试直接“引用”组件:

return (
    <Router>
      <Header />
      <div className="container">
          {routes.map(({ path, Component }) => (
              <Route key={path} exact path={path}>
                  {({ match }) => (
                      <CSSTransition
                          in={match != null}
                          key={path}
                          nodeRef={nodeRef}
                          timeout={1200}
                          classNames="page"
                          onEnter={onEnter}
                          onExit={onExit}
                          unmountOnExit={true}

                      >
                          <div className="page" ref={nodeRef} >
                              <Component />
                          </div>
                      </CSSTransition>
                  )}
              </Route>
          ))}
      </div>
    </Router>
  );

正如预期的那样,这会导致我的应用程序停止工作,因为“nodeRef”返回 false,并且当使用 nodeRef 属性时,节点不会传递给回调函数(例如 onEnter),因为用户已经可以直接访问节点。

所以我现在只需要一种新的方式来做这件事以供将来参考,任何见解或想法都会受到欢迎。

谢谢

【问题讨论】:

  • 我在您包含的代码中的任何地方都看不到findDOMNode。您正在使用的第三方库是否正在调用它?如果是这样,您将无能为力。
  • @Sibox React-Transition-Group 使用它来引用节点。 reactcommunity.org/react-transition-group/transition
  • 如果它被 React Transition Group 调用,那么你无能为力。我不太熟悉那个包的底层机制,但是here's a discussion from their issue tracker
  • @Slbox 非常感谢您的帮助。它让我找到了答案,请参见下文:)

标签: javascript reactjs routes react-router


【解决方案1】:

所以我只想向@Slbox 大声疾呼,他激励我深入挖掘并重新审视这个问题。

免责声明

我不是 javascript 方面的专家或专业程序员,我绝不建议这是这样做的唯一方法,我的演示应该以抽象的方式进行。我的想法仅解释了解决方案所基于的理论前提,而其实现将取决于您自己的架构。

寻找节点'findDOMNode'

因此,在 React Strict 模式下,“FindDomNode”正在被贬值,当您想要引用页面上的元素时,现在更倾向于使用“Ref”友好的方法。像很多人一样,我收到了一条令人讨厌的错误消息,它会弹出一条告诉你“findDOMNode 已在严格模式下贬值”。

用例(为什么会出现问题)

在 React Router 中,我使用来自 'react-transition-group 的 CSSTransition 和基于 Javascript 的动画平台 'GSAP' 的组合创建了一个简单的页面转换。我遇到的问题是我使用 DOM 节点方法将元素引用到反应中的首选方式。

1.重构应用组件

// So the App now has the routes contained inside each component in order for it
// to work and add additional functions and flexibility.

import React from 'react';
import { BrowserRouter as Router } from 'react-router-dom';

import './route.scss';

import Header from './tools/header';
import About from './pages/about';
import Home from './pages/home';

function Routeapp() {


  return (
    <Router>
      <Header />
      <div className="container">
          <Home /> <!-- routes and funcs -->
          <About /> <!-- routes and funcs -->
      </div>
    </Router>
  );
}

export default Routeapp;

2。主页/关于组件

import React, {useRef} from 'react';
import Title from './title';
import { CSSTransition } from 'react-transition-group';
import {  Route} from 'react-router-dom';
import {gsap} from "gsap";


const Home = () => {

    // These two Refs are needed to refer to elements that we will be animating
    const title = useRef(null)
    const info = useRef(null)

    // This Ref will be used to make reference to the page of each component. 
    // My understanding is that this Ref will be used to distinguish between each 
    // component that is using 'CSSTransition' component and also removes the 
    // 'findDOMNode' warning
    const nodeRef = useRef(null)

    // This function is called immediately after the 'enter' 
    // or 'appear' class is applied from CSSTransition component.

    const onEnter = () => {
        gsap.from(
            [title.current,info.current],
            {
                duration: 0.6,
                y: 30,
                delay: 0.6,
                ease: 'power3.inOut',
                opacity: 0,
                stagger: {
                    amount: 0.3,
                },
            }
        );
    };


    // This function is called immediately after the 'exit' 
    // class is applied from CSSTransition component.
    const onExit = () => {
        gsap.to(
            [title.current,info.current],
            {
                duration: 0.6,
                y: -30,

                ease: 'power3.inOut',
                opacity: 0,
                stagger: {
                    amount: 0.15,
                },
            }
        );

    };


  return (

    <Route
        exact path={'/'}
        children={({ match }) => (
            <CSSTransition
                in={match != null}
                // time should not really be longer than the time it takes the animation
                // to leave the scene.
                timeout={1200}
                classNames={'page'}
                nodeRef={nodeRef}
                onEnter={onEnter}
                onExit={onExit}
                unmountOnExit
            >
                <div className={'page'} ref={nodeRef}>
                    <div className="inner">
                        <Title forwardRef={title} lineContent="this is the" lineContent2="Home page" />
                        <div ref={info} className={'infoBox'}>
                            <p className="info">hello stackOverflow and welcome</p>
                        </div>
                    </div>
                </div>
            </CSSTransition>
        )}
    />

  );
};


export default Home;

GSAP and React-Router EXAMPLE

结论

这是我实现这个效果的方法,但是如果有更好或者替代的方法那么请加入讨论和分享。

【讨论】:

    【解决方案2】:

    快速解决方案是:

    ./src/index.js 文件并从此更改:

       ReactDOM.render(
      <React.StrictMode>
        <App />
      </React.StrictMode>,
      document.getElementById('root')
    );
    

    到这里:

    ReactDOM.render(
        <App />
      document.getElementById('root')
    );
    

    【讨论】:

      【解决方案3】:

      @W9914420 的回答指导我找到了解决此问题的方法。

      我只想从所有代码行中添加,最相关的是:

      • 为引用声明一个实例:
          const nodeRef = useRef(null)
      
      • 将该引用作为属性注入到组件中:
          <CSSTransition ``
              in={match != null}
              // time should not really be longer than the time it takes the animation
              // to leave the scene.
              timeout={1200}
              classNames={'page'}
              nodeRef={nodeRef}
              onEnter={onEnter}
              onExit={onExit}
              unmountOnExit
              >
      

      感谢@W9914420 的提示!

      【讨论】:

        猜你喜欢
        • 2021-10-12
        • 2020-09-08
        • 1970-01-01
        • 2021-04-08
        • 2020-07-07
        • 2020-09-23
        • 1970-01-01
        • 1970-01-01
        • 2021-06-09
        相关资源
        最近更新 更多