React挂钩如何在初次使用后跳过特定的useEffect

时间:2020-08-30 15:21:48

标签: reactjs react-hooks

我有以下代码,如何防止<div style="width: 300px">300px x auto<div class="App">.App</div></div> <div style="width: 360px">360px x auto<div class="App">.App</div></div> <div style="width: 400px">400px x auto<div class="App">.App</div></div>在初始渲染时被调用2次?它被AsyncStorage.setItem调用,并且由于[]已更新,因此从AsyncStorage加载的任何内容。完美的解决方案根本不应该调用logs,因为setItem只是从logs中检索出来的。

AsyncStorage

4 个答案:

答案 0 :(得分:1)

我认为包装您的设置状态方法是一种更清洁的方法,可以控制何时应保留日志。像这样:

const AsyncStorage = require("@react-native-community/async-storage")

const useStore = () => {
  const [logs, setLogsState] = useState([])
  const persistLogsRef = useRef(false)

  const setLogs = (updatedLogs) => {
    persistLogsRef.current = true
    setLogsState(updatedLogs)
  }

  useEffect(() => {
    AsyncStorage.getItem("logs").then((newLogs) => setLogsState(newLogs));
  }, [])

  useEffect(() => {
    //Don't want to setItem on initial load or when `logs` was just loaded.
    if (persistLogsRef.current) {
      AsyncStorage.setItem("logs", JSON.stringify(logs));
    }
  }, [logs])

  const addLog = (newText) => {
    setLogs(logs => [
      {text: newText, createdAt: new Date().getTime()},
      ...logs,
    ]);
  }

  return {
    logs,
    addLog,
    //...many other functions that update logs
  }
}

答案 1 :(得分:0)

您可以使用ref作为标志,以指示是否允许设置日志。

const AsyncStorage = require("@react-native-community/async-storage")

const useStore = () => {
  const [logs, setLogs] = useState([]);
  const allowSettingLogs = React.useRef(false);

  useEffect(() => {
    AsyncStorage.getItem("logs").then((newLogs) => setLogs(newLogs));
  }, [])

  useEffect(() => {
    //Don't want to setItem on initial load or when `logs` was just loaded.
    if (allowSettingLogs.current) AsyncStorage.setItem("logs", JSON.stringify(logs));
  }, [logs])

  const addLog = (newText) => {
    allowSettingLogs.current = true;
    setLogs(logs => [
      {text: newText, createdAt: new Date().getTime()},
      ...logs,
    ]);
  }

  return {
    logs,
    addLog,
    //...many other functions that update logs
  }
}

答案 2 :(得分:0)

您可能想包装useEffect并使其忽略第一个更改。

const useEffectIgnoringFirstChange = (fn, deps) => {
    const firstCallRef = useRef(true);

    useEffect(() => {
        if (firstCallRef.current) {
            firstCallRef.current = false;
            return;
        };

        fn()
    }, deps);
}
const useStore = () => {
  const [logs, setLogs] = useState([])

  useEffect(() => {
    AsyncStorage.getItem("logs").then((newLogs) => setLogs(newLogs));
  }, [])

  useEffectIgnoringFirstChange(() => {
    //Don't want to setItem on initial load or when `logs` was just loaded.
    AsyncStorage.setItem("logs", JSON.stringify(logs));
  }, [logs])

  const addLog = (newText) => {
    setLogs(logs => [
      {text: newText, createdAt: new Date().getTime()},
      ...logs,
    ]);
  }

  return {
    logs,
    addLog,
    //...many other functions that update logs
  }
}

答案 3 :(得分:0)

这就是我最终得到的结果,我仍然想知道这是否是最好的解决方案,因此欢迎使用更优雅的解决方案:

const AsyncStorage = require("@react-native-community/async-storage")

const useStore = () => {
  const justLoaded = useRef(true);
  const [logs, setLogs] = useState([])

  useEffect(() => {
    AsyncStorage.getItem("logs").then((newLogs) => {
     justLoaded.current = true;
     setLogs(newLogs));
    }
  }, [])

  useEffect(() => {
    //Don't want to setItem on initial load or when `logs` was just loaded.
    if (justLoaded.current === false) AsyncStorage.setItem("logs", JSON.stringify(logs));
    if (justLoaded.current) justLoaded.current = false;
  }, [logs])

  const addLog = (newText) => {
    setLogs(logs => [
      {text: newText, createdAt: new Date().getTime()},
      ...logs,
    ]);
  }

  return {
    logs,
    addLog,
    //...many other functions that update logs
  }
}
相关问题