背景
所以我有一个简单的例子,一个Form组件(Parent)和多个Input组件(Children)。每个单独的Input组件都将有一个useState
钩子来初始化和管理其值的状态。
问题
与大多数表单一样,我希望将所有数据提交到后端进行处理。然而,问题是我无法从每个子输入组件中检索值的状态。
// app.jsx
import Form from "./Form";
export default function App() {
return <Form />;
}
// Form.jsx
import React from "react";
import Input from "./Input";
const handleSubmit = (e) => {
e.preventDefault();
console.log("Wait, how do I retreive values from Children Inputs?");
};
const Form = () => {
console.log("Form render");
return (
<form onSubmit={handleSubmit}>
Sample Form
<Input initial="username" name="user" />
<Input initial="email" name="email" />
<button type="submit">Submit</button>
</form>
);
};
export default Form;
// Input.jsx
import React from "react";
import useInputValue from "./useInputValue";
const Input = ({ name, initial }) => {
const inputState = useInputValue(initial);
console.log(`${name}'s value: ${inputState.value}`);
return <input {...inputState} />;
};
export default Input;
合理的解决方案
当然,我可以将Input状态提升到Form组件,也许是在obj名称值中。但是,如果我这样做,每次更改输入时,Form都会重新渲染,同时所有的输入。
对我来说,这是不可取的副作用。随着我的Form组件越来越大,每当一个输入发生变化时,重新呈现所有输入(表单内)的成本就会更高。
正因为如此,我想坚持我的决定,让每个单独的输入管理自己的状态,这样,如果一个输入发生变化,并不是所有其他输入都会与父组件一起重新渲染。
问题
如果每个子组件都管理自己的状态,那么父组件是否可以访问该状态的值并执行操作(如表单提交)?
更新
许多回答和评论都提到,这是过早的优化,是所有已知邪恶的根源;我同意,但为了澄清,我用一个简单的例子来问这个问题,因为我想为我目前更复杂的项目找到一个可行的解决方案。我的网络应用程序有一个巨大的表单(所有状态都提升到表单级别),每次输入更改时都会重新呈现。这似乎没有必要,因为一次只更改一个输入。
更新#2以下是我遇到的问题的代码沙盒示例。有两种表单,一种是所有状态由单独的Child输入组件管理,另一种是在表单级别提升所有状态。请尝试输入一些值并检查控制台中的日志消息。可以看到,随着所有状态提升到表单级别,每一次更改都会导致两个输入都被重新呈现。
我认为是的,您可以共享状态。还有3个选项:
- 我建议您使用Formik这样的库。这对你的情况会有所帮助
- 您可以使用useState()钩子作为道具来共享状态
- 使用诸如Redux Toolkit(如果我们谈论的是记忆)、useContext()等工具
如果您想要从输入中获得最终值,请为每个输入分配ref,并使用submit函数中的emailRef.current.value进行访问。
import { useState, useRef, forwardRef } from 'React';
const Input = forwardRef((props, ref) => {
const [value, setValue] = useState('');
return <input ref={ref} value={value} onChange={(e) => {setValue(e.target.value)}} {...props} />;
});
const App = () => {
const emailRef = useRef(null);
const submit = () => {
const emailString = emailRef.current.value
};
return (
<>
<Input ref={emailRef} />
<button onClick={submit}>Submit</button>
</>
);
};
如果家长需要了解孩子的状态,您可以
- 向上移动状态。这是通过传递子级调用的setState函数来解决的(状态数据在父级中可用)
- 使用上下文https://reactjs.org/docs/context.html
- 使用状态管理库,例如redux
在你的简单情况下,我会选择1)