componentDidMount เทียบเท่ากับฟังก์ชัน React / Hooks หรือไม่


99

มีวิธีในการจำลองcomponentDidMountองค์ประกอบการทำงานของปฏิกิริยาผ่านตะขอหรือไม่?

คำตอบ:


199

สำหรับ hooks เวอร์ชันเสถียร (React Version 16.8.0+)

สำหรับ componentDidMount

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

สำหรับ componentDidUpdate

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

สำหรับ componentWillUnmount

useEffect(() => {
  // componentWillUnmount
  return () => {
     // Your code here
  }
}, [yourDependency]);

ดังนั้นในสถานการณ์นี้คุณต้องส่งการอ้างอิงของคุณไปยังอาร์เรย์นี้ สมมติว่าคุณมีสถานะแบบนี้

const [count, setCount] = useState(0);

และเมื่อใดก็ตามที่จำนวนเพิ่มขึ้นคุณต้องการแสดงองค์ประกอบฟังก์ชันของคุณอีกครั้ง ของคุณuseEffectควรมีลักษณะเช่นนี้

useEffect(() => {
  // <div>{count}</div>
}, [count]);

This way whenever your count updates your component will re-render. Hopefully this will help a bit.


Thorough explanation! Is there a way to simulate componentDidReceiveProps?
jeyko

1
I'm not aware of it even if it exists. You can check this thread for it tho github.com/facebook/react/issues/3279
Mertcan Diken

1
Thank you for this as I wasn't aware of the second argument in useState. To anyone reading this, please keep in mind that leaving the second argument undefined will cause your effect to trigger on every render (if I'm not mistaken).
dimiguel

Do you mean dependencies of useEffect (passing a dependency array)? If so yeah if you leave it empty that's a bug in the code. For array deconstruction, you need both [count, setCount] because count is your state variable in this example and setCount is your function to update that state.
Mertcan Diken

Thanks for the answer. The documentation about this is here reactjs.org/docs/hooks-effect.html
Josh

3

Although accepted answer works, it is not recommended. When you have more than one state and you use it with useEffect, it will give you warning about adding it to dependency array or not using it at all.

It sometimes causes the problem which might give you unpredictable output. So I suggest that you take a little effort to rewrite your function as class. There are very little changes, and you can have some components as class and some as function. You're not obligated to use only one convention.

Take this for example

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

This is only for example. so lets not talk about best practices or potential issues with the code. Both of this has same logic but the later only works as expected. You might get componentDidMount functionality with useEffect running for this time, but as your app grows, there are chances that you MAY face some issues. So, rather than rewriting at that phase, it's better to do this at early stage.

Besides, OOP is not that bad, if Procedure-Oriented Programming was enough, we would never have had Object-Oriented Programming. It's painful sometimes, but better (technically. personal issues aside).


1
I did this. I faced issue using hooks. The issue was gone after converting it to class.
Julez

2

There's no componentDidMount on functional components, but React Hooks provide a way you can emulate the behavior by using the useEffect hook.

Pass an empty array as the second argument to useEffect() to run only the callback on mount only.

Please read the documentation on useEffect.

function ComponentDidMount() {
  const [count, setCount] = React.useState(0);
  React.useEffect(() => {
    console.log('componentDidMount');
  }, []);

  return (
    <div>
      <p>componentDidMount: {count} times</p>
      <button
        onClick={() => {
          setCount(count + 1);
        }}
      >
        Click Me
      </button>
    </div>
  );
}

ReactDOM.render(
  <div>
    <ComponentDidMount />
  </div>,
  document.querySelector("#app")
);
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

<div id="app"></div>


0

You want to use useEffect(), which, depending on how you use the function, can act just like componentDidMount().

Eg. you could use a custom loaded state property which is initially set to false, and switch it to true on render, and only fire the effect when this value changes.

Documentation


1
This solution is not ideal. It's a bad idea to use a state value just to determine if component has mounted. Also, if you were to use a property, a ref would be better as it wouldn't trigger another re-render.
Yangshun Tay

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.