Это будет во многом зависеть от ваших конкретных потребностей.То, что вы собираетесь делать с данными формы, сообщит, какую форму вы хотите иметь, а что еще нужно сделать в этом компоненте, будет информировать внутреннюю логику компонента.Но вот как минимум несколько идей:
Один из подходов - объединить все варианты SetField
в один, который принимает функцию обновления состояния.Таким образом, вы можете указать, какое поле обновлять только в функции рендеринга:
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>,
};