reactjs 类组件引用和设置自己的静态变量-函数组件的等价物是什么?

eqqqjvef  于 2023-10-17  发布在  React
关注(0)|答案(1)|浏览(104)

当使用类组件时,我能够设置静态变量,这些变量将在类的每个进一步示例上持久化。这允许我在组件上设置一种firstRun状态,即使多次调用同一个组件也是如此。
我尝试在一个函数式组件中创建这种行为,但是当组件被多次使用时,它似乎每次都忘记了它的状态、引用等。
在下面的代码中,我有两个组件,一个函数和一个类。每个组件在App中被调用三次。在类组件中,我可以直接设置ClassComponent.firstRun,然后我可以在同一组件的进一步包含中引用它。在功能组件中,我已经尝试了相同的useRef,但这似乎只对组件的每个示例有效,并且在每个新组件上都被遗忘。

const { useEffect, useRef } = React;

const FunctionalComponent = (props) => {
  const { id } = props;
  const mounted = useRef(false);
  useEffect(() => {
    if (!mounted.current) {
      console.log('Initial functional component load...', id);
      mounted.current = true;
    } else {
      console.log('Functional component has already been initialised.', id)
    }
  }, []); 
  return (
    <div>Hello, functional component!</div>
  );
};

class ClassComponent extends React.Component {
  constructor(props) {
    super(props);
    this.createSomething();
  }
  
  static firstRun = true;
  
  createSomething() {
    if (ClassComponent.firstRun) {
      console.log('Initial class component load...', this.props.id);
      ClassComponent.firstRun = false;
    } else {
      console.log('Class component has already been initialised.', this.props.id);
    }
  }

  render() {
    return (
      <div>Hello, class component!</div>
    );
  }
}

function App() {
  return (
    <div>
      <ClassComponent id="class-component-1" />
      <ClassComponent id="class-component-2" />
      <ClassComponent id="class-component-3" />
      <FunctionalComponent id="functional-component-1" />
      <FunctionalComponent id="functional-component-2" />
      <FunctionalComponent id="functional-component-3" />
    </div>
  )
}

ReactDOM.render(<App />, document.querySelector("#app"));
<div id="app"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>

类组件工作良好-我得到一个日志的初始负载,然后两个日志说,它已经初始化-伟大的!然而,功能组件记录三个初始加载消息。
我试过使用useState,但据我所知,这只适用于重新渲染,而不是单独的组件占用。在使用useRef时,这似乎也是相同的情况。
我读过关于函数闭包的文章,并试图用下面的代码粗略地实现一个函数,但这又给了我三个Initialised...日志:

const checkInitial = () => {
  let initial = true; 
  return {
    get: function() { return initial },  
    set: function(state) { initial = state; }
  };
}
...
const FunctionalComponent = (props) => {
  const { id } = props;
  const mounted = useRef(false);
  useEffect(() => {
    const firstRun = checkInitial();
    if (firstRun.get()) {
      console.log('Initial...', id);
      firstRun.set(true);
    } else {
      console.log('Already run...', id);
    }
  }, []); 
  return (
    <div>Hello, functional component!</div>
  );
};

我相信设置一个上下文变量可以解决这个问题,但我现在不想使用它。我也知道我可以将状态提升到父级,但我想避免这样做,因为它很可能会导致重新渲染。
这种情况似乎很容易用类组件解决,但这些组件现在已经过时了。有没有一种简单的方法可以完全使用功能性功能/组件来做到这一点?
干杯!干杯!

envsm3lx

envsm3lx1#

任何钩子,无论是useState还是useRef,都是组件的每个示例。
如果你真的想要一个静态变量1,就像你对class组件做的那样-把它存储在function对象本身:

function FunctionComponent({ id }) {
  if (FunctionComponent.firstRun) {
    console.log('Initial function component render...', id);
    FunctionComponent.firstRun = false;
  } else {
    console.log('Function component has already been rendered before.', id);
  }
  return (
    <div>Hello, function component!</div>
  );
}
FunctionComponent.firstRun = true;

更习惯的做法是在定义函数组件的模块作用域中声明一个变量:

let firstRun = true;
function FunctionComponent({ id }) {
  if (firstRun) {
    console.log('Initial function component render...', id);
    firstRun = false;
  } else {
    console.log('Function component has already been rendered before.', id);
  }
  return (
    <div>Hello, function component!</div>
  );
}

如果你不想在每次组件渲染时都显示日志,而只在组件挂载时显示一次,你可以使用一个效果或状态的初始化器:

let firstRun = true;
function FunctionComponent({ id }) {
  useEffect(() => {
    if (firstRun) {
      console.log('Initial function component mount...', id);
      firstRun = false;
    } else {
      console.log('Function component has already been mounted elsewhere.', id);
    }
  }, []);
  return (
    <div>Hello, function component!</div>
  );
}
let firstRun = true;
function FunctionComponent({ id }) {
  const [isFirst] = useState(() => {
    if (firstRun) {
      firstRun = false;
      return true;
    } else {
      return false;
    }
  });
  return (
    <div>Hello, {isFirst && 'first'} function component!</div>
  );
}

1:你可能不需要静态变量。这对于常量来说是可以的,但是一旦你有了有状态的静态变量,它本质上就是全局状态。避免这样。

相关问题