Допустим, у меня есть родительский компонент и дочерний компонент.Родительский компонент состоит из нескольких дочерних компонентов.Родительский компонент содержит и управляет очень сложным и глубоким объектом данных.Каждый дочерний компонент предоставляет пользовательский интерфейс для управления различными дочерними объектами и свойствами основного объекта данных.Всякий раз, когда дочерний компонент изменяет значение свойства в иерархии объекта данных, это изменение должно доходить до основного объекта данных.
Вот как я могу сделать это в классе дочернего компонента, передав объект обратного вызова...
<div>
<button onClick={e => this.setState({propA: e.target.value}, () => props.onChangePropA(this.state.propA)}>Prop A</button>
<button onClick={e => this.setState({propB: e.target.value}, () => props.onChangePropB(this.state.propB)}>Prop B</button>
</div>
По сравнению с тем, как я думаю, мне нужно сделать это с помощью хуков.Основная проблема, которую я вижу, заключается в том, что после завершения изменения состояния опция обратного вызова отсутствует.Поэтому я должен обнаружить его в useEffect и выяснить, какое свойство только что изменилось ...
let prevPropA = props.propA;
let prevPropB = props.propB;
const [propA, setPropA] = useState(props.propA);
const [propB, setPropB] = useState(props.propB);
useEffect(() => {
if (prevPropA != propA) props.onChangePropA(propA);
if (prevPropB != propB) props.onChangePropB(propB);
});
<div>
<button onClick={e => {prevPropA = propA; setPropA(e.target.value)}}>Prop A</button>
<button onClick={e => {prevPropB = propB; setPropB(e.target.value)}}>Prop B</button>
</div>
Я вижу, что этот метод становится чрезвычайно громоздким и грязным.Есть ли более надежный / правильный способ сделать это?
Спасибо
==================================================================
Ниже приведен обновленный пример кода, основанный на Shubham'sответ и отзыв Райана.Шубхэм ответила на вопрос в ответ на вопрос, но Райан предлагает мне привести более подробный пример, чтобы убедиться, что я даю правильную информацию для правильного ответа.Вот пример кода, который более точно следует моей реальной ситуации ... хотя все еще является упрощенным примером.Родительский компонент управляет комментариями пользователей.Представьте, что они могут создавать новые комментарии и выбирать дату или диапазон дат.Они также могут обновить существующие комментарии.Я поместил селектор даты и диапазона дат в его собственный компонент.Поэтому родительский компонент диспетчера комментариев должен иметь возможность создавать / загружать комментарии и передавать связанные даты в компонент выбора даты.Затем пользователь может изменить дату (даты), и эти значения должны быть переданы обратно в родительский менеджер комментариев для последующей отправки на сервер и сохранения.Итак, вы видите, что существует двунаправленный поток значений свойств (даты и т. Д.), Которые могут быть изменены в любое время с любого конца.ПРИМЕЧАНИЕ. Этот новый пример обновляется с использованием метода, аналогичного предложенному Шубхэмом, на основе моего исходного вопроса.
==================================================================
const DateTimeRangeSelector = (props) =>
{
const [contextDateStart, setContextDateStart] = useState(props.contextDateStart);
const [contextDateEnd, setContextDateEnd] = useState(props.contextDateEnd);
const [contextDateOnly, setContextDateOnly] = useState(props.contextDateOnly);
const [contextDateHasRange, setContextDateHasRange] = useState(props.contextDateHasRange);
useEffect(() => { setContextDateStart(props.contextDateStart); }, [ props.contextDateStart ]);
useEffect(() => { if (contextDateStart !== undefined) props.onChangeContextDateStart(contextDateStart); }, [ contextDateStart ]);
useEffect(() => { setContextDateEnd(props.contextDateEnd); }, [ props.contextDateEnd ]);
useEffect(() => { if (contextDateEnd !== undefined) props.onChangeContextDateEnd(contextDateEnd); }, [ contextDateEnd ]);
useEffect(() => { setContextDateOnly(props.contextDateOnly); }, [ props.contextDateOnly ]);
useEffect(() => { if (contextDateOnly !== undefined) props.onChangeContextDateOnly(contextDateOnly); }, [ contextDateOnly ]);
useEffect(() => { setContextDateHasRange(props.contextDateHasRange); }, [ props.contextDateHasRange ]);
useEffect(() => { if (contextDateHasRange !== undefined) props.onChangeContextDateHasRange(contextDateHasRange); }, [ contextDateHasRange ]);
return <div>
<ToggleButtonGroup
exclusive={false}
value={(contextDateHasRange === true) ? ['range'] : []}
selected={true}
onChange={(event, value) => setContextDateHasRange(value.some(item => item === 'range'))}
>
<ToggleButton value='range' title='Specify a date range' >
<FontAwesomeIcon icon='arrows-alt-h' size='lg' />
</ToggleButton>
</ToggleButtonGroup>
{
(contextDateHasRange === true)
?
<DateTimeRangePicker
range={[contextDateStart, contextDateEnd]}
onChangeRange={val => { setContextDateStart(val[0]); setContextDateEnd(val[1]); }}
onChangeShowTime={ val => setContextDateOnly(! val) }
/>
:
<DateTimePicker
selectedDate={contextDateStart}
onChange={val => setContextDateStart(val)}
showTime={! contextDateOnly}
/>
}
</div>
}
const CommentEntry = (props) =>
{
const [activeComment, setActiveComment] = useState(null);
const createComment = () =>
{
return {uid: uuidv4(), content: '', contextDateHasRange: false, contextDateOnly: false, contextDateStart: null, contextDateEnd: null};
}
const editComment = () =>
{
return loadCommentFromSomewhere();
}
const newComment = () =>
{
setActiveComment(createComment());
}
const clearComment = () =>
{
setActiveComment(null);
}
return (
<div>
<Button onClick={() => newComment()} variant="contained">
New Comment
</Button>
<Button onClick={() => editComment()} variant="contained">
Edit Comment
</Button>
{
activeComment !== null &&
<div>
<TextField
value={(activeComment) ? activeComment.content: ''}
label="Enter comment..."
onChange={(event) => { setActiveComment({...activeComment, content: event.currentTarget.value, }) }}
/>
<DateTimeRangeSelector
onChange={(val) => setActiveComment(val)}
contextDateStart={activeComment.contextDateStart}
onChangeContextDateStart={val => activeComment.contextDateStart = val}
contextDateEnd={activeComment.contextDateEnd}
onChangeContextDateEnd={val => activeComment.contextDateEnd = val}
contextDateOnly={activeComment.contextDateOnly}
onChangeContextDateOnly={val => activeComment.contextDateOnly = val}
contextDateHasRange={activeComment.contextDateHasRange}
onChangeContextDateHasRange={val => activeComment.contextDateHasRange = val}
/>
<Button onClick={() => clearComment()} variant="contained">
Cancel
</Button>
<Button color='primary' onClick={() => httpPostJson('my-url', activeComment, () => console.log('saved'))} variant="contained" >
<SaveIcon/> Save
</Button>
</div>
}
</div>
);
}