我正在尝试编写一个通用的React Hook,以允许我更新对象。
我引用了以下内容:Input Hook-(来源: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
})
}
}
};
};
答案 0 :(得分:3)
通常,您的钩子应该接受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);
但是,您可以按照以下说明更新钩子
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>
这样,您为嵌套对象创建了另一个bind方法,也许您可以添加另一个名为array
的东西。希望这能给您一些有关如何改进挂钩的想法。顺便说一下,有很多的方法可以做到这一点,这只是一个例子。可能有更好的方法。
我已经更新了您的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>
);
};