mirror of
https://github.com/facebook/react.git
synced 2026-02-21 19:31:52 +00:00
[react-dom] Fire onReset when automatically resetting forms (#35176)
This commit is contained in:
committed by
GitHub
parent
b8a6bfa22c
commit
dcab44d757
@@ -88,6 +88,7 @@ class Header extends React.Component {
|
||||
<option value="/mouse-events">Mouse Events</option>
|
||||
<option value="/selection-events">Selection Events</option>
|
||||
<option value="/suspense">Suspense</option>
|
||||
<option value="/form-actions">Form Actions</option>
|
||||
<option value="/form-state">Form State</option>
|
||||
<option value="/fragment-refs">Fragment Refs</option>
|
||||
</select>
|
||||
|
||||
113
fixtures/dom/src/components/fixtures/form-actions/index.js
Normal file
113
fixtures/dom/src/components/fixtures/form-actions/index.js
Normal file
@@ -0,0 +1,113 @@
|
||||
const React = window.React;
|
||||
|
||||
const {useState} = React;
|
||||
|
||||
async function defer(timeoutMS) {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(resolve, timeoutMS);
|
||||
});
|
||||
}
|
||||
|
||||
export default function FormActions() {
|
||||
const [textValue, setTextValue] = useState('0');
|
||||
const [radioValue, setRadioValue] = useState('two');
|
||||
const [checkboxValue, setCheckboxValue] = useState([false, true, true]);
|
||||
const [selectValue, setSelectValue] = useState('three');
|
||||
|
||||
return (
|
||||
<form
|
||||
action={async () => {
|
||||
await defer(500);
|
||||
}}
|
||||
onReset={() => {
|
||||
setTextValue('0');
|
||||
setRadioValue('two');
|
||||
setCheckboxValue([false, true, true]);
|
||||
setSelectValue('three');
|
||||
}}>
|
||||
<div style={{display: 'flex'}}>
|
||||
<fieldset style={{flexBasis: 0}}>
|
||||
<legend>type="text"</legend>
|
||||
<input
|
||||
type="text"
|
||||
name="text"
|
||||
value={textValue}
|
||||
onChange={event => setTextValue(event.currentTarget.value)}
|
||||
/>
|
||||
</fieldset>
|
||||
<fieldset style={{flexBasis: 0}}>
|
||||
<legend>type="radio"</legend>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio"
|
||||
value="one"
|
||||
checked={radioValue === 'one'}
|
||||
onChange={() => setRadioValue('one')}
|
||||
/>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio"
|
||||
value="two"
|
||||
checked={radioValue === 'two'}
|
||||
onChange={() => setRadioValue('two')}
|
||||
/>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio"
|
||||
value="three"
|
||||
checked={radioValue === 'three'}
|
||||
onChange={() => setRadioValue('three')}
|
||||
/>
|
||||
</fieldset>
|
||||
<fieldset style={{flexBasis: 0}}>
|
||||
<legend>type="checkbox"</legend>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="checkbox"
|
||||
value="one"
|
||||
checked={checkboxValue[0]}
|
||||
onChange={event => {
|
||||
const checked = event.currentTarget.checked;
|
||||
setCheckboxValue(pending => [checked, pending[1], pending[2]]);
|
||||
}}
|
||||
/>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="checkbox"
|
||||
value="two"
|
||||
checked={checkboxValue[1]}
|
||||
onChange={event => {
|
||||
const checked = event.currentTarget.checked;
|
||||
setCheckboxValue(pending => [pending[0], checked, pending[2]]);
|
||||
}}
|
||||
/>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="checkbox"
|
||||
value="three"
|
||||
checked={checkboxValue[2]}
|
||||
onChange={event => {
|
||||
const checked = event.currentTarget.checked;
|
||||
setCheckboxValue(pending => [pending[0], pending[1], checked]);
|
||||
}}
|
||||
/>
|
||||
</fieldset>
|
||||
<fieldset style={{flexBasis: 0}}>
|
||||
<legend>select</legend>
|
||||
<select
|
||||
name="select"
|
||||
value={selectValue}
|
||||
onChange={event => setSelectValue(event.currentTarget.value)}>
|
||||
<option value="one">one</option>
|
||||
<option value="two">two</option>
|
||||
<option value="three">three</option>
|
||||
</select>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div>
|
||||
<input type="reset" />
|
||||
<input type="submit" />
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
@@ -6562,5 +6562,7 @@ export const HostTransitionContext: ReactContext<TransitionStatus> = {
|
||||
|
||||
export type FormInstance = HTMLFormElement;
|
||||
export function resetFormInstance(form: FormInstance): void {
|
||||
ReactBrowserEventEmitterSetEnabled(true);
|
||||
form.reset();
|
||||
ReactBrowserEventEmitterSetEnabled(false);
|
||||
}
|
||||
|
||||
@@ -1596,6 +1596,57 @@ describe('ReactDOMForm', () => {
|
||||
expect(divRef.current.textContent).toEqual('Current username: acdlite');
|
||||
});
|
||||
|
||||
it('should fire onReset on automatic form reset', async () => {
|
||||
const formRef = React.createRef();
|
||||
const inputRef = React.createRef();
|
||||
|
||||
let setValue;
|
||||
const defaultValue = 0;
|
||||
function App({promiseForUsername}) {
|
||||
const [value, _setValue] = useState(defaultValue);
|
||||
setValue = _setValue;
|
||||
|
||||
return (
|
||||
<form
|
||||
ref={formRef}
|
||||
action={async formData => {
|
||||
Scheduler.log(`Async action started`);
|
||||
await getText('Wait');
|
||||
}}
|
||||
onReset={() => {
|
||||
setValue(defaultValue);
|
||||
}}>
|
||||
<input
|
||||
ref={inputRef}
|
||||
text="text"
|
||||
name="amount"
|
||||
value={value}
|
||||
onChange={event => setValue(event.currentTarget.value)}
|
||||
/>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
const root = ReactDOMClient.createRoot(container);
|
||||
await act(() => root.render(<App />));
|
||||
|
||||
// Dirty the controlled input
|
||||
await act(() => setValue('3'));
|
||||
expect(inputRef.current.value).toEqual('3');
|
||||
|
||||
// Submit the form. This will trigger an async action.
|
||||
await submit(formRef.current);
|
||||
assertLog(['Async action started']);
|
||||
|
||||
// We haven't reset yet.
|
||||
expect(inputRef.current.value).toEqual('3');
|
||||
|
||||
// Action completes. onReset has been fired and values reset manually.
|
||||
await act(() => resolveText('Wait'));
|
||||
assertLog([]);
|
||||
expect(inputRef.current.value).toEqual('0');
|
||||
});
|
||||
|
||||
it('requestFormReset schedules a form reset after transition completes', async () => {
|
||||
// This is the same as the previous test, except the form is updated with
|
||||
// a userspace action instead of a built-in form action.
|
||||
|
||||
Reference in New Issue
Block a user