私はreacthooksフォームを使用しており、配列にマッピングして入力をフォームに出力することで出力されるフォームのデフォルト値を設定しようとしています。配列をこのようなオブジェクトに縮小しました。{name0:"fijs",name1:"3838"...}
手動でデフォルト値に渡すと、入力にマップされて入力されます。ただし、reduce関数を実行している変数からそれらを入力すると、データは入力されません。最初のレンダリングでは未定義だからだと思います。useEffectを使用してみましたが、うまくいきませんでした。
これは私が取り組んでいるコードの一部です
const test = formState?.reduce((obj, item, idx) => {
return { ...obj, [`${item.name}${idx}`]: "fdsjfs" };
}, {});
const { register, handleSubmit, errors } = useForm({
defaultValues: test,
});
console.log(test);
これが全部です
import { useQuery, gql, useMutation } from "@apollo/client";
import { useEffect, useState } from "react";
import { v4 as uuidv4 } from "uuid";
import { useForm } from "react-hook-form";
const INPUT_VALUES = gql`
query GetInputValues {
allFormInputVals {
data {
name
_id
type
}
}
}
`;
const ADD_INPUT_VALUES = gql`
mutation AddInputValues(
$name: String!
$type: String!
$index: Int!
$ID: ID!
) {
createFormInputVal(
data: {
name: $name
type: $type
index: $index
formRoot: { connect: $ID }
}
) {
name
}
}
`;
const Home = () => {
const blankFormInput = {
__typename: "FormInputVal",
name: "test",
_id: uuidv4(),
type: "text",
};
const [formState, setFormState] = useState([blankFormInput]);
const [formStateVals, setFormStateVals] = useState(undefined);
const { loading, error, data } = useQuery(INPUT_VALUES);
const [createFormInputVal, { data: createInputData }] = useMutation(
ADD_INPUT_VALUES
);
useEffect(() => {
setFormState(data?.allFormInputVals?.data);
}, [data]);
const test = formState?.reduce((obj, item, idx) => {
return { ...obj, [`${item.name}${idx}`]: "fdsjfs" };
}, {});
const { register, handleSubmit, errors } = useForm({
defaultValues: test,
});
console.log(test);
const onSubmit = (data) => console.log(data);
console.log(errors);
const addInput = async () => {
const blanktext = {
__typename: "FormInputVal",
name: "Product Image",
_id: uuidv4(),
type: "text",
};
setFormState([...formState, { ...blanktext }]);
console.log(formState);
const res = await createFormInputVal({
variables: {
name: "test",
type: "text",
index: 0,
ID: "291541554941657608",
},
}).catch(console.error);
console.log(res);
};
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<>
<form onSubmit={handleSubmit(onSubmit)}>
<input type="button" value="Add Form Input" onClick={addInput} />
{formState?.map((val, idx) => {
const nameId = `name${idx}`;
const typeId = `type-${idx}`;
return (
<div key={val._id}>
{val.type === "text" && (
<>
<label htmlFor={nameId}>{`${val.name} #${idx + 1}`}</label>
<input
type="text"
name={nameId}
id={nameId}
className={val.type}
ref={register()}
/>
{/* <label htmlFor={typeId}>{`Type #${idx + 1}`}</label>
<select name={typeId} id={typeId} className={val.type}>
{data.allFormInputVals.data.map((item) => {
return (
<option key={item._id} value={item.type}>
{item.type}
</option>
);
})}
</select> */}
</>
)}
</div>
);
})}
<button type="submit">Save Form</button>
</form>
</>
);
};
export default Home;
更新:apiからリセットしてuseEffectを試しましたが、これが解決策だと思いましたが、それでもサイコロはありません。
const { register, handleSubmit, errors, reset } = useForm();
useEffect(() => {
const result = test; // result: { firstName: 'test', lastName: 'test2' }
reset(result); // asynchronously reset your form values
}, [reset]);
更新:フォームを独自のコンポーネントに抽象化しましたが、それでも機能しません。
Form.js
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { useQuery, gql, useMutation } from "@apollo/client";
import { v4 as uuidv4 } from "uuid";
const ADD_INPUT_VALUES = gql`
mutation AddInputValues(
$name: String!
$type: String!
$index: Int!
$ID: ID!
) {
createFormInputVal(
data: {
name: $name
type: $type
index: $index
formRoot: { connect: $ID }
}
) {
name
}
}
`;
export default function Form({ formState, setFormState }) {
const test = formState?.reduce((obj, item, idx) => {
return { ...obj, [`${item.name}${idx}`]: "fdsjfs" };
}, {});
console.log(test);
const { register, handleSubmit, errors } = useForm({ defaultValues: test });
const [formStateVals, setFormStateVals] = useState(undefined);
// console.log(test);
const onSubmit = (data) => console.log(data);
console.log(errors);
const addInput = async () => {
const blanktext = {
__typename: "FormInputVal",
name: "Product Image",
_id: uuidv4(),
type: "text",
};
setFormState([...formState, { ...blanktext }]);
console.log(formState);
const res = await createFormInputVal({
variables: {
name: "test",
type: "text",
index: 0,
ID: "291541554941657608",
},
}).catch(console.error);
console.log(res);
};
const [createFormInputVal, { data: createInputData }] = useMutation(
ADD_INPUT_VALUES
);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input type="button" value="Add Form Input" onClick={addInput} />
{formState?.map((val, idx) => {
const nameId = `name${idx}`;
const typeId = `type-${idx}`;
return (
<div key={val._id}>
{val.type === "text" && (
<>
<label htmlFor={nameId}>{`${val.name} #${idx + 1}`}</label>
<input
type="text"
name={nameId}
id={nameId}
className={val.type}
ref={register()}
/>
{/* <label htmlFor={typeId}>{`Type #${idx + 1}`}</label>
<select name={typeId} id={typeId} className={val.type}>
{data.allFormInputVals.data.map((item) => {
return (
<option key={item._id} value={item.type}>
{item.type}
</option>
);
})}
</select> */}
</>
)}
</div>
);
})}
<button type="submit">Save Form</button>
</form>
);
}
index.js
import { useQuery, gql, useMutation } from "@apollo/client";
import { useEffect, useState } from "react";
import { v4 as uuidv4 } from "uuid";
import Form from "../components/Form";
const INPUT_VALUES = gql`
query GetInputValues {
allFormInputVals {
data {
name
_id
type
}
}
}
`;
const Home = () => {
const blankFormInput = {
__typename: "FormInputVal",
name: "test",
_id: uuidv4(),
type: "text",
};
const [formState, setFormState] = useState([blankFormInput]);
const { loading, error, data } = useQuery(INPUT_VALUES);
useEffect(() => {
const formData = data?.allFormInputVals?.data;
setFormState(formData);
}, [data]);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<>
<Form formState={formState} setFormState={setFormState} />
</>
);
};
export default Home;
フォームを独自のコンポーネントに抽出し、データがフェッチされたときにのみレンダリングすることができます。このようuseForm
に、子コンポーネントで使用する場合、デフォルト値が適切に設定されます。
const Home = () => {
const { loading, error, data } = useQuery(INPUT_VALUES)
const blankFormInput = {
__typename: "FormInputVal",
name: "test",
_id: uuidv4(),
type: "text",
}
const [formState, setFormState] = useState([blankFormInput])
// other code
if (loading) {
return <p>Loading...</p>
}
return <MyForm defaultValues={formState} />
}
構造を変更したくない場合は、データの準備ができたときにsetValueを使用して入力値を設定できます。
useEffect(() => {
const formData = data?.allFormInputVals?.data
setFormState(formData)
formData?.forEach((item, idx) => {
setValue(`${item.name}${idx}`, 'whatever')
})
}, [data])
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加