Recoil 中的动态原子键

2024-05-13

我正在尝试创建一个动态表单,其中表单输入字段是根据 API 返回的数据呈现的。

由于atom需要有一个唯一的键,我尝试将它包装在一个函数中,但是每次我更新字段值或重新安装组件(尝试更改选项卡)时,我都会收到一条警告:

我在这里做了一个小的运行示例https://codesandbox.io/s/zealous-night-e0h4jt?file=/src/App.tsx https://codesandbox.io/s/zealous-night-e0h4jt?file=/src/App.tsx(与下面相同的代码):

import React, { useEffect, useState } from "react";
import { atom, RecoilRoot, useRecoilState } from "recoil";
import "./styles.css";

const textState = (key: string, defaultValue: string = "") =>
  atom({
    key,
    default: defaultValue
  });

const TextInput = ({ id, defaultValue }: any) => {
  const [text, setText] = useRecoilState(textState(id, defaultValue));

  const onChange = (event: any) => {
    setText(event.target.value);
  };

  useEffect(() => {
    return () => console.log("TextInput unmount");
  }, []);

  return (
    <div>
      <input type="text" value={text} onChange={onChange} />
      <br />
      Echo: {text}
    </div>
  );
};

export default function App() {
  const [tabIndex, setTabIndex] = useState(0);

  // This would normally be a fetch request made by graphql or inside useEffect
  const fields = [
    { id: "foo", type: "text", value: "bar" },
    { id: "hello", type: "text", value: "world" }
  ];

  return (
    <div className="App">
      <RecoilRoot>
        <form>
          <button type="button" onClick={() => setTabIndex(0)}>
            Tab 1
          </button>
          <button type="button" onClick={() => setTabIndex(1)}>
            Tab 2
          </button>

          {tabIndex === 0 ? (
            <div>
              <h1>Fields</h1>
              {fields.map((field) => {
                if (field.type === "text") {
                  return (
                    <TextInput
                      key={field.id}
                      id={field.id}
                      defaultValue={field.value}
                    />
                  );
                }
              })}
            </div>
          ) : (
            <div>
              <h1>Tab 2</h1>Just checking if state is persisted when TextInput
              is unmounted
            </div>
          )}
        </form>
      </RecoilRoot>
    </div>
  );
}

这在后坐力的情况下也可能吗?我的意思是它似乎有效,但我不能忽视这些警告。


这个答案 https://stackoverflow.com/a/71528025/438273展示了如何使用记忆手动管理原子的多个实例。

但是,如果您的defaultValue对于每个使用实例都不会改变,那么 Recoil 已经提供了一个实用程序,可以为您处理此创建和记忆:atomFamily https://recoiljs.org/docs/api-reference/utils/atomFamily。我将引用上一个链接中的一些相关信息(但请阅读全部内容以充分理解):

...您可以通过记忆模式自己实现这一点。但,Recoil为您提供此模式atomFamily公用事业。原子族代表原子的集合。你打电话时atomFamily它将返回一个函数,该函数提供RecoilState原子基于您传入的参数。

The atomFamily本质上提供了从参数到原子的映射。您只需要提供一个密钥atomFamily它将为每个底层原子生成一个唯一的密钥。这些原子密钥可用于持久性,因此必须在应用程序执行过程中保持稳定。参数也可能在不同的调用点生成,我们希望等效的参数使用相同的底层原子。因此,使用值相等而不是引用相等atomFamily参数。这对可用于参数的类型施加了限制。atomFamily接受基本类型,或者可以包含数组、对象或基本类型的数组或对象。

这是一个工作示例,展示了如何使用您的id and defaultValue(作为元组的值的唯一组合)作为使用实例时的参数atomFamily每个输入的状态:

body { font-family: sans-serif; }
input[type="text"] { font-size: 1rem; padding: 0.5rem; }
<div id="root"></div><script src="https://unpkg.com/[email protected] /cdn-cgi/l/email-protection/umd/react.development.js"></script><script src="https://unpkg.com/[email protected] /cdn-cgi/l/email-protection/umd/react-dom.development.js"></script><script src="https://unpkg.com/[email protected] /cdn-cgi/l/email-protection/umd/recoil.min.js"></script><script src="https://unpkg.com/@babel/[email protected] /cdn-cgi/l/email-protection/babel.min.js"></script><script>Babel.registerPreset('tsx', {presets: [[Babel.availablePresets['typescript'], {allExtensions: true, isTSX: true}]]});</script>
<script type="text/babel" data-type="module" data-presets="tsx,react">

// import ReactDOM from 'react-dom';
// import type {ReactElement} from 'react';
// import {atomFamily, RecoilRoot, useRecoilState} from 'recoil';

// This Stack Overflow snippet demo uses UMD modules instead of the above import statments
const {atomFamily, RecoilRoot, useRecoilState} = Recoil;

const textInputState = atomFamily<string, [id: string, defaultValue?: string]>({
  key: 'textInput',
  default: ([, defaultValue]) => defaultValue ?? '',
});

type TextInputProps = {
  id: string;
  defaultValue?: string;
};

function TextInput ({defaultValue = '', id}: TextInputProps): ReactElement {
  const [value, setValue] = useRecoilState(textInputState([id, defaultValue]));

  return (
    <div>
      <input
        type="text"
        onChange={ev => setValue(ev.target.value)}
        placeholder={defaultValue}
        {...{value}}
      />
    </div>
  );
}

function App (): ReactElement {
  const fields = [
    { id: 'foo', type: 'text', value: 'bar' },
    { id: 'hello', type: 'text', value: 'world' },
  ];

  return (
    <RecoilRoot>
      <h1>Custom defaults using atomFamily</h1>
      {fields.map(({id, value: defaultValue}) => (
        <TextInput key={id} {...{defaultValue, id}} />
      ))}
    </RecoilRoot>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));

</script>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Recoil 中的动态原子键 的相关文章

随机推荐

  • 使用 css resize:both 调整表格单元格的大小;不使用表

    使用 css resize both 调整表格单元格大小不适用于表格 我需要调整表格及其单元格的大小 可以使用 css 调整大小 css resize both 在 div 中有效 但在表标签中无效 table border 1 tr td
  • Google 我的商家 API - 帐户 ID 位置

    GET https mybusiness googleapis com v4 accounts accountId locations locationId reviews reviewId https mybusiness googlea
  • 未加载 Firebird 扩展

    我正在尝试在 PHP 中使用 Firebird 扩展 我有扩展文件 php pdo firebird dll php interbase dll in my ext文件夹 我将它们添加到我的php ini像这样文件 PHP PDO FIRE
  • 音频html标签无法快进或快退控制

    我正在使用音频 html 标签从我的上传服务器加载音频 但我不知道为什么我的音频无法像往常一样循环 快进或快退控制 我的音频 标题 Accenpt Ranges bytes Connection Keep Alive Content Len
  • Jetpack 中的波浪框组成

    有没有办法用Canvas制作一个顶部有波浪形的盒子 我想知道这个效果是否可以直接用Canvas来实现 不需要有滚动动画 不太清楚你为什么在谈论Canvas 要裁剪这样的视图 您可以使用自定义Shape并将其应用到您的视图中Modifier
  • 如何在 VS Code 中打开模拟器或连接 LD Player 以实现 flutter?

    我想开发 flutter 应用程序 但我的笔记本电脑没有足够的 RAM 只有 4 GB 因此 经过在互联网上进行大量广泛的研究 我安装并设置了 flutter sdk android sdk 和 VS Code 但是 当我尝试运行示例应用程
  • 在 C# 中将 ulong 映射到 long ?

    我正在尝试将 ulong 映射到 long 反之亦然 将 uint 映射到 int 反之亦然 如下所示 为了将值保存在具有签名类型的 MS SQL 数据库中仅限整数和大整数 我这样做是因为我必须检查 在数据库中 一个数字 uint ulon
  • “mvn”不被识别为内部或外部命令、可操作程序或批处理文件

    可能是之前问过问题 但我发现了非常奇怪的错误 当我跑步时mvn versionbin 中的命令给出了版本和其他信息 但是 当我跑到垃圾箱外面时 它会出现异常 下面提到的结果 C Program Files apache maven 3 0
  • 从字符串中的链接中删除基本 URL

    我有一个带有图像链接的字符串 image link raw http website com files 2012 10 image001 png 现在我想删除http website com然后就得到 files 2012 10 imag
  • 无法执行'x86_64-conda_cos6-linux-gnu-gcc':没有这样的文件或目录(pysam安装)

    我正在尝试安装 pysam 执行后 python path to pysam master setup py build 这个错误的产生是 unable to execute x86 64 conda cos6 linux gnu gcc
  • 升级到 5.4 但“php -v”仍然返回旧版本

    我使用的是 OSX Lion 10 7 5 正如建议的如何在 Mac OS X 中升级 PHP https stackoverflow com questions 2526085 how do i upgrade php in mac os
  • 什么是多重重继承?

    我将以下称为 多重重新继承 直接继承一个类一次 并通过继承其一个或多个后代来间接继承一次或多次 通过继承一个类的两个或多个后代来间接继承一个类两次或多次 我想知道它是否存在以及如何明确访问嵌入的子对象 1 Professional C 2n
  • 在第一页加载时触发 jquery 脚本,然后不再为该用户触发?

    我在我的网站上使用这个 jQuery 模态窗口脚本 http www zurb com playground reveal modal plugin http www zurb com playground reveal modal plu
  • Bipush 在 JVM 中如何工作?

    我知道 iload 接受整数 1 到 5 但是如何使用 bipush 指令扩展到更高的数字 特定整数如何与字节码一起存储 有几种不同的指令可用于推送整数常量 最小的是iconst 指令 这些只是一个字节 因为该值是在操作码本身中编码的 ic
  • 使 flake8 区分未定义函数和星型导入

    我有一个相当大的项目 我试图在发布之前清理它 但是当我运行 flake8 时 我得到了大量的 F405
  • lambda 表达式是多线程的吗?

    lambda 表达式是多线程的吗 假设当你将数学公式编写为 lambda 方法时 当你将其传递给另一个方法时 它会是多线程的吗 不是100 清楚你问的是什么 您是否想问 lambda 是否自然地在不同的线程上运行 如果是这样 则它们只是 S
  • Swing GUI 出现 IntelliJ 错误“contentPane 无法设置为 null。”从终端编译时

    当我从 IntelliJ 编译我的项目时 没有任何问题 我的程序运行顺利 但是当我尝试使用 javac 从终端编译它时 警告 注意 Victor presentation TableControllerMenu java 使用未经检查或不安
  • 加载 highchart 时 Android 错误膨胀类

    我正在尝试加载highcharts via Dialog 下面是我的代码 Gradle implementation com highsoft highcharts highcharts 9 0 1 XML
  • 如何使组合键唯一?

    I am making a database of students in one school Here is what I have so far 如果您不喜欢阅读 请跳至 简而言之 部分 问题是我对这个设计并不满意 我想要的组合gra
  • Recoil 中的动态原子键

    我正在尝试创建一个动态表单 其中表单输入字段是根据 API 返回的数据呈现的 由于atom需要有一个唯一的键 我尝试将它包装在一个函数中 但是每次我更新字段值或重新安装组件 尝试更改选项卡 时 我都会收到一条警告 我在这里做了一个小的运行示