使用React Hooks卸载组件时如何访问状态?

时间:2020-02-28 17:39:28

标签: javascript reactjs state react-hooks use-effect

使用常规React可能会发生以下情况:

node --version

在React Hooks中,可以这样写:

class NoteEditor extends React.PureComponent {

    constructor() {
        super();

        this.state = {
            noteId: 123,
        };
    }

    componentWillUnmount() {
        logger('This note has been closed: ' + this.state.noteId);
    }

    // ... more code to load and save note

}

function NoteEditor { const [noteId, setNoteId] = useState(123); useEffect(() => { return () => { logger('This note has been closed: ' + noteId); // bug!! } }, []) return '...'; } 返回的内容仅在组件卸载之前执行一次,但是状态(如上面的代码所示)将是陈旧的。

一种解决方案是将useEffect作为依赖项传递,但是效果将在每个渲染器上运行,而不仅仅是一次。或使用参考,但这很难维护。

那么,有没有推荐的模式可以使用React Hook来实现呢?

使用常规的React,可以从组件中的任何位置访问状态,但是使用钩子似乎只有复杂的方法,每种方法都有严重的缺点,或者我只是想念一些东西。

有什么建议吗?

2 个答案:

答案 0 :(得分:8)

useState()useReducer()的一种特殊形式,因此您可以用一个完整的reducer来获取当前状态并解决闭包问题。

NoteEditor

import React, { useEffect, useReducer } from "react";

function reducer(state, action) {
  switch (action.type) {
    case "set":
      return action.payload;
    case "unMount":
      console.log("This note has been closed: " + state); // This note has been closed: 201
      break;
    default:
      throw new Error();
  }
}

function NoteEditor({ initialNoteId }) {
  const [noteId, dispatch] = useReducer(reducer, initialNoteId);

  useEffect(function logBeforeUnMount() {
    return () => dispatch({ type: "unMount" });
  }, []);

  useEffect(function changeIdSideEffect() {
    setTimeout(() => {
      dispatch({ type: "set", payload: noteId + 1 });
    }, 1000);
  }, []);

  return <div>{noteId}</div>;
}
export default NoteEditor;

应用

import React, { useState, useEffect } from "react";
import "./styles.css";
import NoteEditor from "./note-editor";

export default function App() {
  const [notes, setNotes] = useState([100, 200, 300]);

  useEffect(function removeNote() {
    setTimeout(() => {
      setNotes([100, 300]);
    }, 2000);
  }, []);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      {notes.map(note => (
        <NoteEditor key={`Note${note}`} initialNoteId={note} />
      ))}
    </div>
  );
}

答案 1 :(得分:1)

useRef() 来救援。

由于 ref 是可变的并且在组件的生命周期内一直存在,所以我们可以使用它来存储当前值,只要它更新,并且仍然可以在我们的 的清理函数中访问该值>useEffect 通过 ref 的值 .current 属性。

所以会有一个额外的 useEffect() 来在状态改变时保持 ref 的值更新。

示例代码段

const [value, setValue] = useState();
const valueRef = useRef();

useEffect(() => {
  valueRef.current = value;
}, [value]);

useEffect(() => {
  return function cleanup() {
    console.log(valueRef.current);
  };
}, []);

感谢 https://www.timveletta.com/blog/2020-07-14-accessing-react-state-in-your-component-cleanup-with-hooks/ 的作者。请参阅此链接进行深潜。