formik の FieldArray を扱うときに、key に index を使用したくない
2020-04-08
linter 的に良くないので、回避方法を模索しました。
ちなみに、公式サイトは諦めているみたいです、楽だしね。
import {
Field,
FieldArray,
FieldArrayConfig,
Form,
Formik,
FormikConfig,
} from "formik";
import React, { FC, useCallback, useMemo, useState } from "react";
import uniqid from "uniqid";
type Hoge = {
fuga: string;
piyo: number;
};
type AppValues = {
hoges: Hoge[];
};
type HogesProperty = {
handleClickRemoveButton: () => void;
key: string;
};
const App: FC = () => {
const initialValues = useMemo<FormikConfig<AppValues>["initialValues"]>(
() => ({
hoges: [],
}),
[],
);
const handleSubmit = useCallback<FormikConfig<AppValues>["onSubmit"]>(
(values) => {
console.log(values);
},
[],
);
const [hogesProperties, setHogesProperties] = useState<HogesProperty[]>([]);
const renderHoges = useCallback<NonNullable<FieldArrayConfig["children"]>>(
({ push, remove }) => {
const handleClickAddButton = () => {
const key = uniqid();
push({
fuga: "",
piyo: 0,
});
setHogesProperties((prevHogesProperties) =>
([] as typeof hogesProperties).concat(prevHogesProperties, [
{
key,
handleClickRemoveButton: () => {
setHogesProperties((prevHogesProperties) => {
const index = prevHogesProperties.findIndex(
({ key: prevKey }) => key === prevKey,
);
// かなり強引
remove(index);
return prevHogesProperties.filter(
(_, prevIndex) => index !== prevIndex,
);
});
},
},
]),
);
};
const hogesFields = hogesProperties.map(
({ handleClickRemoveButton, key }, index) => (
<div key={key}>
<Field name={`hoges.${index}.fuga`} />
<Field name={`hoges.${index}.piyo`} type="number" />
{key}
<button onClick={handleClickRemoveButton} type="button">
remove
</button>
</div>
),
);
return (
<div>
<button onClick={handleClickAddButton} type="button">
add
</button>
{hogesFields}
</div>
);
},
[hogesProperties, setHogesProperties],
);
return (
<Formik initialValues={initialValues} onSubmit={handleSubmit}>
<Form>
<FieldArray name="hoges">{renderHoges}</FieldArray>
<button type="submit">submit</button>
</Form>
</Formik>
);
};
export default App;
remove を呼ぶタイミングがかなり強引なんですが、ここしか思いつかず…。
container を量産したくないケースでは使えそうですが、パフォーマンスはあまり良くなさそうです。