在React的功能组件中,有方法通过钩子来模拟componentDidMount吗?


当前回答

useLayoutEffect钩子是React钩子中ComponentDidMount的最佳替代方案。 useLayoutEffect钩子在渲染UI之前执行,useEffect钩子在渲染UI之后执行。根据您的需要使用它。 示例代码:

import { useLayoutEffect, useEffect } from "react";

export default function App() {
  useEffect(() => {
    console.log("useEffect Statements");
  }, []);

  useLayoutEffect(() => {
    console.log("useLayoutEffect Statements");
  }, []);
  return (
    <div>
      <h1>Hello Guys</h1>
    </div>
  );
}
 

其他回答

useEffect()钩子允许我们实现componentDidMount功能,componentDidUpdate componentWillUnMount功能。

useEffect()的不同语法允许实现上述每一种方法。

我)componentDidMount

useEffect(() => {
  //code here
}, []);

(二)componentDidUpdate

useEffect(() => {
  //code here
}, [x,y,z]);

//where x,y,z are state variables on whose update, this method should get triggered

3) componentDidUnmount

useEffect(() => {
  //code here
  return function() {
    //code to be run during unmount phase
  }
}, []);

你可以查看官方react网站获取更多信息。hook的官方反应页面

关于钩子内异步函数的信息:

效果回调是同步的,以防止竞争条件。把async函数放在里面:

useEffect(() => {
  async function fetchData() {
    // You can await here
    const response = await MyAPI.getData(someId);
    // ...
  }
  fetchData();
}, [someId]); // Or [] if effect doesn't need props or state

您希望使用useEffect(),这取决于您如何使用函数,可以像componentDidMount()一样工作。

如。你可以使用一个自定义的加载状态属性,初始设置为false,并在呈现时将其切换为true,并且仅在该值发生变化时触发效果。

文档

虽然公认的答案是可行的,但不建议使用。当你有多个状态并且你和useEffect一起使用它时,它会警告你是否将它添加到依赖数组或者根本不使用它。

它有时会导致问题,可能会产生不可预测的输出。因此,我建议您花点精力将函数重写为类。有很少的变化,您可以将一些组件作为类,一些作为函数。您没有义务只使用一种约定。

以这个为例

function App() {
  const [appointments, setAppointments] = useState([]);
  const [aptId, setAptId] = useState(1);

  useEffect(() => {
    fetch('./data.json')
      .then(response => response.json())
      .then(result => {
        const apts = result.map(item => {
          item.aptId = aptId;
          console.log(aptId);
          setAptId(aptId + 1);
          return item;
        })
        setAppointments(apts);
      });
  }, []);

  return(...);
}

and

class App extends Component {
  constructor() {
    super();
    this.state = {
      appointments: [],
      aptId: 1,
    }
  }

  componentDidMount() {
    fetch('./data.json')
      .then(response => response.json())
      .then(result => {
        const apts = result.map(item => {
          item.aptId = this.state.aptId;
          this.setState({aptId: this.state.aptId + 1});
          console.log(this.state.aptId);
          return item;
        });
        this.setState({appointments: apts});
      });
  }

  render(...);
}

这只是举个例子。因此,让我们不要谈论代码的最佳实践或潜在问题。两者的逻辑相同,但后者只能按预期工作。此时,你可能会获得componentDidMount功能和useEffect,但随着应用程序的发展,你可能会面临一些问题。所以,与其在那个阶段重写,不如在早期就重写。

此外,面向对象并不是那么糟糕,如果面向过程编程就足够了,我们就永远不会有面向对象编程了。有时会很痛苦,但更好(技术上来说。暂且把个人问题放在一边)。

在react钩子中没有完全等价的componentDidMount。


根据我的经验,react钩子在开发时需要不同的心态,一般来说,你不应该将它与componentDidMount等类方法进行比较。

尽管如此,还是有一些方法可以使用钩子来产生与componentDidMount类似的效果。

解决方案1:

useEffect(() => {
  console.log("I have been mounted")
}, [])

解决方案2:

const num = 5

useEffect(() => {
  console.log("I will only run if my deps change: ", num)
}, [num])

方案三(带功能):

useEffect(() => {
  const someFunc = () => {
    console.log("Function being run after/on mount")
  }
  someFunc()
}, [])

解决方案4 (useCallback):

const msg = "some message"

const myFunc = useCallback(() => {
  console.log(msg)
}, [msg])

useEffect(() => {
  myFunc()
}, [myFunc])

解决方案5(变得有创意):

export default function useDidMountHook(callback) {
  const didMount = useRef(null)

  useEffect(() => {
    if (callback && !didMount.current) {
      didMount.current = true
      callback()
    }
  })
}

值得注意的是,只有当其他解决方案都不适合您的用例时,才应该真正使用解决方案5。如果你决定你需要解决方案5,那么我建议使用这个预先制作的钩子use-did-mount。

来源(更多细节):在react钩子中使用componentDidMount