JotaiJotai

状態
原始和灵活的 React 状态管理

原子中的 Atom

atom() 创建一个原子配置,它是一个对象,但它没有值。 Atom 配置没有字符串键,我们用引用相等性来标识它们。 换句话说,我们可以像 key 一样使用原子配置。

在 useState 中存储原子配置

首先,我们可以在 useState 中存储一个原子配置。

const Component = ({ atom1, atom2 }) => {
const [selectedAtom, setSelectedAtom] = useState(atom1);
const [value] = useAtom(selectedAtom);
return (
<div>
Selected value: {value}
<button onClick={() => setSelectedAtom(atom1)}>Select an atom</button>
<button onClick={() => setSelectedAtom(atom2)}>
Select another atom
</button>
</div>
);
};

请注意,我们可以将原子配置作为 props 传递。

它可能没有任何意义,但我们可以按需创建原子配置。

const Component = () => {
const [currentAtom, setCurrentAtom] = useState(() => atom(0));
const [count, setCount] = useAtom(currentAtom);
return (
<div>
Count: {count} <button onClick={() => setCount((c) => c + 1)}>+1</button>
<button onClick={() => setCurrentAtom(atom(0))}>Create new</button>
</div>
);
};

在原子中存储原子配置

同样,我们可以将一个原子配置存储为另一个原子的值。

const firstNameAtom = atom("Tanjiro");
const lastNameAtom = atom("Kamado");
const showingNameAtom = atom(firstNameAtom);
const Component = () => {
const [nameAtom, setNameAtom] = useAtom(showingNameAtom);
const [name] = useAtom(nameAtom);
return (
<div>
Name: {name}
<button onClick={() => setNameAtom(firstNameAtom)}>
Show First Name
</button>
<button onClick={() => setNameAtom(lastNameAtom)}>Show Last Name</button>
</div>
);
};

可以创建派生原子。

const derivedNameAtom = atom((get) => {
const nameAtom = get(showingNameAtom);
return get(nameAtom);
});
// 或者更短的版本
const derivedNameAtom = atom((get) => get(get(showingNameAtom)));

为了避免混淆原子中的内容,明确命名原子很重要。 此外,TypeScript 类型信息也会有所帮助。

在原子中存储原子配置数组

最后,atom pattern 中的 atom 是将一个 atom config 数组存储到一个 atom 中。

const countsAtom = atom([atom(1), atom(2), atom(3)]);
const Counter = ({ countAtom }) => {
const [count, setCount] = useAtom(countAtom);
return (
<div>
{count} <button onClick={() => setCount((c) => c + 1)}>+1</button>
</div>
);
};
const Parent = () => {
const [counts, setCounts] = useAtom(countsAtom);
const addNewCount = () => {
const newAtom = atom(0);
setCounts((prev) => [...prev, newAtom]);
};
return (
<div>
{counts.map((countAtom) => (
<Counter countAtom={countAtom} key={countAtom} />
))}
<button onClick={addNewCount}>Add</button>
</div>
);
};

这种方法的好处是,如果你增加一个计数, 只有相应的 Counter 组件重新渲染,没有其他组件重新渲染。

重要的是要注意 anAtom.toString() 返回一个唯一的 id,它可以用作 map 中的 key

给 TypeScript 用户的提示

<Counter countAtom={countAtom} key={`${countAtom}`} />

在原子中存储原子配置映射

同样,我们可以存储对象映射而不是数组。

const pricesAtom = atom({
apple: atom(15),
orange: atom(12),
pineapple: atom(25),
});
const Fruit = ({ name, priceAtom }) => {
const [price] = useAtom(priceAtom);
return (
<div>
{name}: {price}
</div>
);
};
const Parent = () => {
const [prices] = useAtom(pricesAtom);
return (
<div>
{Object.keys(prices).map((name) => (
<Fruit name={name} priceAtom={prices[name]} key={name} />
))}
</div>
);
};