如何操作上下文 - 将函数附加到上下文或将调度包装在钩子中?

2024-01-29

我想知道操作和公开新的 React Context 的推荐最佳实践是什么。

操纵上下文状态的最简单方法似乎是将一个函数附加到调度的上下文(usereducer) 或设置状态 (useState)一旦调用就改变其内部值。

export const TodosProvider: React.FC<any> = ({ children }) => {
  const [state, dispatch] = useReducer(reducer, null, init);

  return (
    <Context.Provider
      value={{
        todos: state.todos,
        fetchTodos: async id => {
          const todos = await getTodos(id);
          console.log(id);
          dispatch({ type: "SET_TODOS", payload: todos });
        }
      }}
    >
      {children}
    </Context.Provider>
  );
};

export const Todos = id => {
  const { todos, fetchTodos } = useContext(Context);
  useEffect(() => {
    if (fetchTodos) fetchTodos(id);
  }, [fetchTodos]);
  return (
    <div>
      <pre>{JSON.stringify(todos)}</pre>
    </div>
  );
};

然而,我被告知直接公开和使用反应上下文对象可能不是一个好主意,并被告知将其包装在一个钩子内。

export const TodosProvider: React.FC<any> = ({ children }) => {
  const [state, dispatch] = useReducer(reducer, null, init);

  return (
    <Context.Provider
      value={{
        dispatch,
        state
      }}
    >
      {children}
    </Context.Provider>
  );
};

const useTodos = () => {
  const { state, dispatch } = useContext(Context);
  const [actionCreators, setActionCreators] = useState(null);

  useEffect(() => {
    setActionCreators({
      fetchTodos: async id => {
        const todos = await getTodos(id);
        console.log(id);
        dispatch({ type: "SET_TODOS", payload: todos });
      }
    });
  }, []);

  return {
    ...state,
    ...actionCreators
  };
};

export const Todos = ({ id }) => {
  const { todos, fetchTodos } = useTodos();
  useEffect(() => {
    if (fetchTodos && id) fetchTodos(id);
  }, [fetchTodos]);

  return (
    <div>
      <pre>{JSON.stringify(todos)}</pre>
    </div>
  );
};

我在这里为这两种变体制作了运行代码示例:https://codesandbox.io/s/mzxrjz0v78?fontsize=14 https://codesandbox.io/s/mzxrjz0v78?fontsize=14

所以现在我有点困惑这两种方法中哪一种是正确的方法?


使用绝对没有问题useContext直接在组件中。然而,它强制必须使用上下文值的组件知道要使用什么上下文。

如果您希望在应用程序中有多个组件使用 TodoProvider 上下文,或者您的应用程序中有多个上下文,则可以使用自定义挂钩来简化它

使用上下文时还必须考虑的另一件事是,您不应该在每个渲染上创建一个新对象,否则所有正在使用的组件context即使没有任何改变,也会重新渲染。为此,您可以使用useMemo hook

const Context = React.createContext<{ todos: any; fetchTodos: any }>(undefined);

export const TodosProvider: React.FC<any> = ({ children }) => {
  const [state, dispatch] = useReducer(reducer, null, init);
  const context = useMemo(() => {
    return {
      todos: state.todos,
      fetchTodos: async id => {
        const todos = await getTodos(id);
        console.log(id);
        dispatch({ type: "SET_TODOS", payload: todos });
      }
    };
  }, [state.todos, getTodos]);
  return <Context.Provider value={context}>{children}</Context.Provider>;
};

const getTodos = async id => {
  console.log(id);
  const response = await fetch(
    "https://jsonplaceholder.typicode.com/todos/" + id
  );
  return await response.json();
};
export const useTodos = () => {
  const todoContext = useContext(Context);
  return todoContext;
};
export const Todos = ({ id }) => {
  const { todos, fetchTodos } = useTodos();
  useEffect(() => {
    if (fetchTodos) fetchTodos(id);
  }, [id]);
  return (
    <div>
      <pre>{JSON.stringify(todos)}</pre>
    </div>
  );
};

工作演示 https://codesandbox.io/s/w7w5485xxw

EDIT:

Since getTodos只是一个不能改变的函数,它使得 使用它作为更新参数的意义useMemo?

通过才有意义getTodos如果 getTodos 方法正在更改并且在功能组件内被调用,则到 useMemo 中的依赖项数组。通常你会使用以下方法来记住该方法useCallback因此,它不会在每个渲染上创建,但仅当其封闭范围的任何依赖项发生更改以更新其词法范围内的依赖项时才创建。现在,在这种情况下,您需要将其作为参数传递给依赖项数组。

但就您的情况而言,您可以省略它。

另外你将如何处理初始效果。说如果你要打电话 当提供商安装时, useEffect 挂钩中的“getTodos”?你能记住吗 那个电话也是如此?

您只需在初始安装时调用的 Provider 中产生一个效果

export const TodosProvider: React.FC<any> = ({ children }) => {
  const [state, dispatch] = useReducer(reducer, null, init);
  const context = useMemo(() => {
    return {
      todos: state.todos,
      fetchTodos: async id => {
        const todos = await getTodos(id);
        console.log(id);
        dispatch({ type: "SET_TODOS", payload: todos });
      }
    };
  }, [state.todos]);
  useEffect(() => {
      getTodos();
  }, [])
  return <Context.Provider value={context}>{children}</Context.Provider>;
};
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何操作上下文 - 将函数附加到上下文或将调度包装在钩子中? 的相关文章

  • VM428:7 未捕获类型错误:无法在 :7:17 处读取 null 属性(读取“CodeMirror”)

    代码运行良好 但我不明白在哪里收到此错误 VM428 7 Uncaught TypeError Cannot read properties of null reading CodeMirror at
  • 我无法在我的反应本机上使用加载的应用程序。它不会正常工作

    我不断收到此错误 错误截图 https i stack imgur com 88KPa png 这是我用来导入自定义谷歌字体的代码 import React useState from react import Home from scre
  • 无法读取未定义错误的属性“匹配”

    我试图在 React JS 前端显示一些文本来代替个人资料图像 当它不可用时 基本上 我将当前客户名称传递给一个函数 该函数提取名称中所有单词的第一个字符 我能够仅显示名称 但是当我执行函数调用时 出现 无法读取未定义的属性 匹配 错误 并
  • VSCode 在 React 的 JSX 中错误地格式化三进制

    我正在运行 VSCode 来开发我的 React 应用程序 我有一个简单的三元 isLoading
  • 从react-loadable中命名webpack块

    我已经成功在我的项目中添加了react loadable库以启用代码分割 我发现的唯一问题是webpack生成的块没有命名 它们被赋予了整数名称 我的反应可加载使用代码是 const AppRootLoadable Loadable loa
  • 如何使用函数组件和 React Router v5 拦截 React SPA 中的后退按钮

    我正在 React 中的 SPA 中工作 不使用 React Router 来创建任何路由 我不需要允许用户导航到特定页面 想想多页调查问卷 按顺序填写 但是 当用户按下后退按钮时在浏览器上 我不希望他们退出整个应用程序 我希望能够在用户按
  • 如何将数组与 setState 一起使用?

    我目前正在使用以下命令将数组映射到 setState 但没有设置任何内容 也没有记录任何错误 如果我明确地逐行写出它 它就会起作用 关于如何解决这个问题有什么想法或建议吗 使用数组设置状态 不设置状态 const myData messag
  • 在 useRef() 中存储回调

    这是一个可变引用的示例 它存储来自反应过度的博客 https overreacted io making setinterval declarative with react hooks function useInterval callb
  • 让Webpack不捆绑文件

    所以现在我正在使用一个原型 我们使用 webpack 用于构建 tsx 文件和复制 html 文件 和 webpack dev server 之间的组合来提供开发服务 正如您可以假设的那样 我们也使用 React 和 ReactDOM 作为
  • 如何使用 JSX 和 Lodash 重复一个元素 n 次

    我在我的应用程序中使用 React JSX 和 Lodash 来实现我想要的 我需要根据条件重复某个元素一定次数 我该怎么做呢 这是元素 span span 我这样分配它 let card if data hand 8 or more ca
  • React setState回调返回值

    我是 React 新手 我希望实现这种流程 set the state execute a function f an async one which returns a promise set the state again return
  • 如何创建显示/隐藏 Docusaurus 项目中所有详细标签状态的按钮?

    根据讨论here https stackoverflow com questions 58579048 how to add or remove the open attribute from all details tags in a r
  • 如何将类组件中的 props 发送到功能组件?

    我是 ReactJS 的初学者 需要知道如何将一个页面中的 props 值发送到另一个页面 道具位于第一页上我可以获取类组件值如何获取另一页中的值 提前致谢 墙色 jsx import React Component from react
  • 无法验证 CSRF 令牌的真实性 Rails/React

    我的 Rails 应用程序中有一个 React 组件 我正在尝试使用它fetch 发送一个POST对于我在本地主机上托管的 Rails 应用程序 这给了我错误 ActionController InvalidAuthenticityToke
  • 如何在React中处理多个路由器

    假设我们有一个网络应用程序 它通常有很多视图 例如索引页面 管理面板 帮助页面 联系人等 我在主index js 中使用react router dom 来处理它们 它工作得很好 但是现在我在开发管理面板时遇到了问题 它是 index js
  • 使用相同的 props 来反应备忘录重新渲染?

    有一个相当简单的功能组件 如果给出相同的道具 我想阻止它被重新渲染 下面是网上找的 貌似不行 知道我应该做什么吗 就我而言 props 由一组对象组成 其中一些也是嵌套对象 这也许是一个线索 export const DataTable R
  • 监听 redux 动作

    我想创建一个可重用的 redux 表模块 它将存储和更新页码 显示的总页数等 我可以在所有页面之间共享这些模块 但是 我需要更新操作来触发刷新数据操作 该操作将根据页面到达不同的端点 因此 可能类似于页面特定的监听 RefreshData
  • 发布到 npm 时出现问题

    所以我尝试使用 React 构建一个开源项目并将其推送到 npm 问题是 我的组件虽然在测试环境中运行良好 安装到其他组件 但当我将其发布到 npm 并下载包并尝试访问它时 它给了我一个错误 这是代码的一个小示例 import React
  • 向 ReduxReducer 添加回调

    是否有任何错误 反模式 就 React Redux 中的思考 中添加了一个回调action data转化为行动 reducer ACTION FOR REDUCER var x 123 if action data callback act
  • Next.js:如何将 source-map-explorer 与 Next.js 一起使用

    我想分析我的 Next js 构建源地图浏览器 https www npmjs com package source map explorer 有人可以帮我编写脚本吗 对于 React CRA 我使用以下脚本 build analyze n

随机推荐

  • 如何使用 CoreData 执行计算查询

    我有 T SQL 背景 所以 CoreData 的东西对我来说有点新鲜 我正在制作一个应用程序原型 该应用程序最终将使用 MS SQL 后端 Web 服务进行查询 在我的后端 我的 t sql 查询将是这样的 SELECT SQRT SQU
  • “关闭变量会导致性能稍差”。如何?

    在回答 SO 问题时 我被告知我的解决方案将引入变量闭包 因此它的性能会稍差 所以我的问题是 怎么会出现倒闭呢 它将如何影响性能 这里是question https stackoverflow com questions 24696991
  • 有效管理数据变更

    我有一张名为 Bookings 的表 该表包含表示针对特定服务进行的预订的数据 具有许多变量 不久前 我遇到了当前数据结构的问题 即影响时间 日期或价格的预订的任何更改都会影响其他相关的财务记录 日期的预订列表等 我当时的解决方案是创建一个
  • swift webrtc 修改 CMSampleBuffer 以应用一些滤镜效果

    我想在localVideo中添加一些滤镜效果 所以我修改了CMSampleBuffer 转换为 UIImage 使用VNFaceDetector检测人脸boundingBox 将我的滤镜图像添加到相机图像中 转换回 CMSampleBuff
  • Haskell 中 2 个列表的笛卡尔积

    我希望在 Haskell 中生成 2 个列表的笛卡尔积 但我不知道该怎么做 笛卡尔积给出列表元素的所有组合 xs 1 2 3 ys 4 5 6 cartProd a gt b gt a b cartProd xs ys gt 1 4 1 5
  • 如何快速拍照并保存到应用程序本地

    我正在开发一个应用程序 在当前阶段 当用户拍照时 照片将存储在应用程序本地 IBAction func CameraAction sender UIButton let picker UIImagePickerController pick
  • 重新调整复杂类型对象时,SoapObject Result 返回 anyType{} 作为值

    我正在我的 Android 应用程序中调用 Web 服务 方法是 getGramaNiladhariData 我得到的结果是 SoapObject result SoapObject envelope bodyIn Log d WS Str
  • Excel VBA:我们可以通过名称引用列吗?

    我想通过标题名称引用列 当前列是第四列 标题名称是 首选项 该列由 是 或 否 组成 第 5 列标题是 原因 仅当 偏好 栏为 否 时才填写 我的代码是 Private Sub CommandButton1 Click Dim i As I
  • 限制日期时间选择器中的时间间隔

    我在用着this http www eyecon ro bootstrap datepicker 选择日期和时间 该文档没有提到时间选择器 但它无论如何都可以工作 HTML div class dateTimePicker div
  • SQL 将值更改为大写或小写

    如何使sql select语句中的字段全部大写或小写 Example 从人中选择名字 如何使名字始终返回大写 同样始终返回小写 SELECT UPPER firstname FROM Person SELECT LOWER firstnam
  • 使用 ruby​​ 应用程序时出现remove_entry_secure错误

    我正在尝试使用 docsplit 将 PDF 文件拆分为图像 但我的红宝石安装似乎有问题 我每次都会收到以下错误 usr lib ruby 1 8 fileutils rb 694 in remove entry secure parent
  • 我可以在没有递归和堆栈的情况下对二叉树进行中序遍历吗?

    谁能给我一个在不使用递归和不使用堆栈的情况下按顺序遍历二叉树的解决方案 第二次编辑 我认为这是正确的 除了通常的node left child 和node right child 之外 还需要node isRoot node isLeftC
  • SQL:递归路径

    是否可以在 SQL 中创建 树解析器 我有一张桌子 ID Name Parent 1 a 2 b 1 3 c 1 4 d 3 现在我想要一个返回的 SQL 查询 ID PATH 1 a 2 a b 3 a c 4 a c d 这可以用 SQ
  • 动态设置搜索提示

    有谁知道如何动态设置android搜索对话框提示 T 尝试做类似的事情
  • 如何使 Twitter Bootstrap 工具提示易于访问?

    如您所知 Twitter 引导工具提示无法访问 即屏幕阅读器无法读取它们 为了实现这一目标 应该做以下事情 拨打电话后tooltip 函数中 生成的文本元素 包含工具提示文本的元素 应该添加一个新属性 aria hidden true 原始
  • 如何获取数组元素的类型?

    我正在写一个多态性迭代数组的 PL pgSQL 函数 我有兴趣使用FOREACH 但是我不知道如何声明具有正确类型的临时变量 我的函数如下 有关更多信息 请参阅第 4 行的注释 CREATE OR REPLACE FUNCTION uniq
  • Firestore在更新后获取Field.increment的值而不读取文档数据

    有没有办法检索使用更新的文档字段的更新值firestore FieldValue increment不索要文件 var countersRef db collection system doc counters await counters
  • Python 类型暗示​​一个充满 myclass 对象的双端队列

    使用 Python 3 6 或更高版本 我想输入提示函数myfunc返回 MyClass 的对象 我该如何暗示myqueue is a deque洋溢着MyClass物体 from collections import deque glob
  • R如何控制颜色条/图例的间距

    我想绘制叶绿素浓度图 但这些值的分散方式使得图例变得不可读 见图 所以我试图控制颜色条 图例中颜色的间距 我想让它均匀分布 同时保持地图本身的不均匀中断 下面的示例非常简化 适用于栅格图 但对于 image plot 也是如此 librar
  • 如何操作上下文 - 将函数附加到上下文或将调度包装在钩子中?

    我想知道操作和公开新的 React Context 的推荐最佳实践是什么 操纵上下文状态的最简单方法似乎是将一个函数附加到调度的上下文 usereducer 或设置状态 useState 一旦调用就改变其内部值 export const T