【问题标题】:Save value from custom hook to state将值从自定义挂钩保存到状态
【发布时间】:2021-09-28 14:13:12
【问题描述】:

我正在尝试使用 useState 将自定义挂钩(为服务器获取数据)中的值保存到功能组件状态,因为我稍后需要更改此值,并且在更改后需要重新渲染。所以期望的行为是:

  1. 将 State 变量设置为来自自定义挂钩的值
  2. 使用此状态变量渲染内容
  3. 修改按钮点击状态
  4. 使用新状态重新渲染

我尝试的是:

  • 将 useState 的初始值设置为我的钩子: const [data, setData] = useState<DataType[] | null>(useLoadData(id).data) 但是数据总是空的。

  • 在 useEffect() 挂钩中设置状态:

    useEffect(()=>{
        const d = useLoadData(id).data
        setData(d)
    }, [id])
    

    但这向我显示了错误警告:错误:无效的挂钩调用。 Hooks 只能在函数组件内部调用。

  • 这样做:

    const [data, setData] = useState<DocumentType[]>([])
    const dataFromServer = useLoadData(id).data
    
    useEffect(()=>{
      if (dataFromServer){
        setData(dataFromServer)
      }
    }, [dataFromServer])
    

    导致:错误:超出最大更新深度。当组件在 useEffect 中调用 setState 时,可能会发生这种情况,但 useEffect 要么没有依赖数组,要么每次渲染时其中一个依赖项都发生了变化。

什么是适合我的用例的解决方案?

【问题讨论】:

  • 选项 3 是您应该定位的目标。您需要多久从useLoadData 挂钩加载数据?你能分享一下这个实现吗?
  • @Steffi:如果您的问题得到解答,请接受答案。这有助于更广泛的社区找到一个好问题的正确答案。

标签: javascript reactjs typescript react-native react-hooks


【解决方案1】:

看起来您的自定义挂钩每次使用时都会返回一个新数组。

解决方案 1:更改挂钩以返回数组的“缓存”实例。

function useLoadData(id) {
  const [data, setData] = useState([]);

  useEffect(() => {
    loadData(id).then(setData);
  }, [id]);

  // good
  return data;

  //bad
  //return data.map(...)

  //bad
  //return data.filter(...)

  //etc
}

codesandbox.io link

解决方案 2:更改您的挂钩以接受 setData 作为参数。

function useLoadData(id, setData) {
  useEffect(() => {
    loadData(id).then(setData);
  }, [id]);
}

这里我告诉钩子在哪里存储数据,以便自定义钩子和组件中的按钮都可以写入同一个地方。

codesandbox.io link

完整示例:

import React from "react";
import ReactDOM from "react-dom";
import { useState, useEffect } from "react";

// simulates async data loading
function loadData(id) {
  return new Promise((resolve) => setTimeout(resolve, 1000, [id, id, id]));
}

// a specialized 'stateless' version of custom hook
function useLoadData(id, setData) {
  useEffect(() => {
    loadData(id).then(setData);
  }, [id]);
}

function App() {
  const [data, setData] = useState(null);

  useLoadData(123, setData);

  return (
    <div>
      <div>Data: {data == null ? "Loading..." : data.join()}</div>
      <div>
        <button onClick={() => setData([456, 456, 456])}>Change data</button>
      </div>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById("container"));

【讨论】:

    猜你喜欢
    • 2020-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-23
    相关资源
    最近更新 更多