我正在尝试编写一个通用的,以允许我更新对象。
我参考了: Input (来源:https://rangle.io/blog/simplifying-controlled-inputs-with-hooks/)并做了一些修改:
import { useState } from "react";
export const useForm = initialObject => {
const [values, setValues] = useState(initialObject);
return {
values: values || initialObject,
setValues,
reset: () => setValues({}),
bind: {
onChange: (event) => {
setValues({
...values,
[event.target.id]: event.target.value
})
}
}
};
};这在单层对象中运行得很好:
{ name: '', type: '' }但是对于具有嵌套值的对象:
{ name: '', type: '', price: { dollar: 5, cents: 20 } }我太确定该如何替换[event.target.id]来读取嵌套级别的对象。
有人能给我建议吗?
更新:
import { useState } from "react";
export const useForm = initialObject => {
const [values, setValues] = useState(initialObject);
return {
values: values || initialObject,
setValues,
reset: () => setValues({}),
bind: {
onChange: (event) => {
// ###need make this part generic###
// event.target.id will be "price.dollar"
values['price']['dollar'] = event.target.value;
setValues({
...values
})
}
}
};
};发布于 2019-11-25 08:48:34
通常,您的钩子应该接受name和value来更新本地状态。显然,您的钩子总是接收一个event,您提取event.target.id作为字段的name,event.target.value作为字段的值。我建议您更新钩子以接收name和value作为参数,并让使用钩子的组件定义什么是name和value。
根据您的钩子,您可以像这样更新嵌套对象。请看这个例子。
import React, { useState } from "react";
import ReactDOM from "react-dom";
const useForm = initialObject => {
const [values, setValues] = useState(initialObject);
return {
values: values || initialObject,
setValues,
reset: () => setValues({}),
bind: {
onChange: event => {
setValues({
...values,
[event.target.id]: event.target.value
});
}
}
};
};
const App = () => {
const { values, bind } = useForm({
name: "",
type: "",
price: { dollar: 5, cents: 20 }
});
return (
<div>
Hook state:
<pre>{JSON.stringify(values, null, 4)}</pre>
<div>
<div>
<label>
Name : <br />
<input id="name" onChange={bind.onChange} />
</label>
</div>
<div>
<label>
Type : <br />
<input id="type" onChange={bind.onChange} />
</label>
</div>
<div>
<label>
Price - Dollar : <br />
<input
id="dollar"
type="number"
onChange={e => {
bind.onChange({
target: {
id: "price",
value: { ...values.price, [e.target.id]: e.target.value }
}
});
}}
/>
</label>
</div>
<div>
<label>
Price - Cents : <br />
<input
id="cents"
type="number"
onChange={e => {
bind.onChange({
target: {
id: "price",
value: { ...values.price, [e.target.id]: e.target.value }
}
});
}}
/>
</label>
</div>
</div>
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);更新(11/25/2019):
但是,您可以按以下方式更新钩子
const useForm = initialObject => {
const [values, setValues] = useState(initialObject);
return {
values: values || initialObject,
setValues,
reset: () => setValues({}),
bind: {
onChange: event => {
setValues({
...values,
[event.target.id]: event.target.value
});
},
onNestedChange: (event, name) => {
setValues({
...values,
[name]: {
...values[name],
[event.target.id]: event.target.value,
}
})
}
}
};
};然后,在您的输入中,可以如下所示:
<div>
<label>
Price - Dollar : <br />
<input
id="dollar"
type="number"
onChange={e => bind.onNestedChange(e, 'price')}
/>
</label>
</div>
<div>
<label>
Price - Cents : <br />
<input
id="cents"
type="number"
onChange={e => bind.onNestedChange(e, 'price')}
/>
</label>
</div>这样,您就为嵌套对象创建了另一个绑定方法,也许还可以添加另一个名为array之类的方法。希望这能给你一些关于如何改进钩子的想法。顺便说一句,有很多可以做到这一点,这只是一个例子。也许有更好的方法来做到这一点。
更新2 (11/25/2019):
我更新了您的useForm钩子,现在可以将嵌套对象属性设置为您的状态。但是,我还没有用数组进行测试,这可能会导致问题。
const useForm = initialObject => {
const [values, setValues] = useState(initialObject);
// Copied and modified from https://stackoverflow.com/a/18937118/11125492
const nestedObjectSet = (obj, path, value) => {
let schema = obj; // a moving reference to internal objects within obj
const pList = path.split(".");
const len = pList.length;
for (let i = 0; i < len - 1; i++) {
let elem = pList[i];
if (!schema[elem]) schema[elem] = {};
schema = schema[elem];
}
schema[pList[len - 1]] = value;
};
// handleOnChange update state value
const handleOnChange = event => {
let newValues = Object.assign({}, values);
nestedObjectSet(newValues, event.target.name, event.target.value);
setValues(newValues);
};
return {
values: values || initialObject,
setValues,
reset: () => setValues({}),
bind: {
onChange: handleOnChange
}
};
};你可以这样用它。注意,我已经将对象的key从event.target.id更改为event.target.name。key应该用name而不是id设置
const App = () => {
const { values, bind } = useForm({
name: "",
type: "",
price: { dollar: 5, cents: 20 }
});
return (
<div>
Hook state:
<pre>{JSON.stringify(values, null, 4)}</pre>
<div>
<div>
<label>
Name : <br />
<input name="name" {...bind} />
</label>
</div>
<div>
<label>
Type : <br />
<input name="type" {...bind} />
</label>
</div>
<div>
<label>
Price - Dollar : <br />
<input name="price.dollar" type="number" {...bind} />
</label>
</div>
<div>
<label>
Price - Cents : <br />
<input name="price.cents" type="number" {...bind} />
</label>
</div>
</div>
</div>
);
};https://stackoverflow.com/questions/59027749
复制相似问题