我正在使用ReasonReact编写表单。我使用reducerComponent
和一条记录作为状态。假设我有这样的东西:
type state = {
field1: string,
field2: int,
};
type action =
| SetField1(string)
| SetField2(int);
let component = ReasonReact.reducerComponent("SomeComponent");
let make = ( _children) => {
...component,
initialState: () => {field1: "", field2: 0},
reducer: (action, state) => switch(action) {
| SetField1(value) => ReasonReact.Update({...state, field1: value})
| SetField2(value) => ReasonReact.Update({...state, field2: value})
},
render: ({state, send}) =>
<div>
<input value={state.field1} onChange={e => send(SetField1(getValue(e)))} />
<input value={state.field2 |> string_of_int} onChange={e => send(SetField2(e |> getValue |> int_of_string))} />
</div>,
}
在此示例中,只有2个字段,但是如果有例如30个字段,该如何处理?这是否意味着我必须创建30个不同的动作并在reducer中处理30次?这是很多无关紧要的代码。有什么方法可以更动态地修改记录,或者我应该为状态(对象,Js.t)使用另一种结构?
为澄清起见,我在两种情况下使用了这种形式:
答案 0 :(得分:0)
这将在很大程度上取决于您的特定需求。您将要对表单数据进行的操作将告知您希望它具有什么形状,而在此组件中需要执行的其他操作将通知该组件的内部逻辑。但是至少这里有一些想法:
一种方法是将所有SetField
变体组合为仅带有状态更新功能的一种。这样,您可以仅在render函数中指定要更新的字段:
type action =
| SetField(state => state);
let make = _children => {
...component,
initialState: () => {field1: "", field2: 0},
reducer: (action, state) =>
switch (action) {
| SetField(updater) => ReasonReact.Update(updater(state))
},
render: ({state, send}) =>
<div>
<input
value={state.field1}
onChange={
e => {
let value = getValue(e);
send(SetField(state => {...state, field1: value}));
}
}
/>
<input
value={string_of_int(state.field2)}
onChange={
e => {
let value = e |> getValue |> int_of_string;
send(SetField(state => {...state, field2: value}));
}
}
/>
</div>,
};
但是因为React事件不是不可改变的,而且实际上是由React本身重用的,所以这有点容易出错。解决方法增加了冗长性。因此,除非您可以排除这种冗长的说法,否则这种方法可能没有太多意义。
如果在此组件中要做的只是更新状态,则可以完全删除action
类型。这消除了上面的一些详细信息,但其他方面存在相同的问题,并且灵活性也大大降低。
let make = _children => {
...component,
initialState: () => {field1: "", field2: 0},
reducer: (updater, state) =>
ReasonReact.Update(updater(state)),
render: ({state, send}) =>
<div>
<input
value={state.field1}
onChange={
e => {
let value = getValue(e);
send(state => {...state, field1: value});
}
}
/>
<input
value={string_of_int(state.field2)}
onChange={
e => {
let value = e |> getValue |> int_of_string;
send(state => {...state, field2: value});
}
}
/>
</div>,
};