我正在尝试创建一个动态表单,其中表单输入字段是根据 API 返回的数据呈现的。
由于atom需要有一个唯一的键,我尝试将它包装在一个函数中,但是每次我更新字段值或重新安装组件(尝试更改选项卡)时,我都会收到一条警告:
我在这里做了一个小的运行示例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>
);
}
Run Code Online (Sandbox Code Playgroud)
这在后坐力的情况下也可能吗?我的意思是它似乎有效,但我不能忽视这些警告。
这个答案展示了如何使用记忆手动管理原子的多个实例。
但是,如果您的defaultValue每个使用实例都不会更改,那么 Recoil 已经提供了一个实用程序,可以为您处理此创建和记忆操作:atomFamily。我将引用上一个链接中的一些相关信息(但请阅读全部内容以充分理解):
...您可以通过记忆模式自己实现这一点。但是,Recoil为您提供了这种模式的
atomFamily实用程序。原子族代表原子的集合。当您调用时,atomFamily它将返回一个函数,该函数RecoilState根据您传入的参数提供原子。本质
atomFamily上提供了从参数到原子的映射。您只需为 提供一个密钥atomFamily,它就会为每个底层原子生成一个唯一的密钥。这些原子密钥可用于持久性,因此必须在应用程序执行过程中保持稳定。参数也可能在不同的调用点生成,我们希望等效的参数使用相同的底层原子。因此,参数使用值相等而不是引用相等atomFamily。这对可用于参数的类型施加了限制。atomFamily接受基本类型,或者可以包含数组、对象或基本类型的数组或对象。
下面是一个工作示例,展示了在为每个输入使用状态实例时如何使用idand defaultValue(作为元组的唯一值组合)作为参数:atomFamily
body { font-family: sans-serif; }
input[type="text"] { font-size: 1rem; padding: 0.5rem; }Run Code Online (Sandbox Code Playgroud)
<div id="root"></div><script src="https://unpkg.com/react@17.0.2/umd/react.development.js"></script><script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.development.js"></script><script src="https://unpkg.com/recoil@0.6.1/umd/recoil.min.js"></script><script src="https://unpkg.com/@babel/standalone@7.17.7/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>Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4490 次 |
| 最近记录: |