0Pricing
React Native Academy · 강의

양식 제출 및 초기화

handleSubmit으로 양식 제출을 처리하고, 검증된 값으로 API를 호출하며, 성공 또는 서버 측 오류 메시지를 표시한 뒤 성공하면 양식을 초기화합니다.

양식 제출 및 초기화은(는) CoddyKit의 무료 React Native Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 React Native Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. React Native Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.

The handleSubmit Wrapper

handleSubmit from useForm is a higher-order function that wraps your submit handler. When called, it first runs all validation rules. If every field passes, it calls your handler with the typed form data. If any field fails, it populates formState.errors and does not call your handler. Never read form values directly from state inside the submit handler — always use the typed data argument that handleSubmit provides.

const { handleSubmit } = useForm<LoginForm>();

async function onSubmit(data: LoginForm) {
  // data is fully typed — guaranteed to have passed validation
  console.log(data.email, data.password);
  await authApi.login(data.email, data.password);
}

// Wire to button:
<Button title='Log In' onPress={handleSubmit(onSubmit)} />

Making an API Call in the Submit Handler

The submit handler is an async function — handleSubmit handles the Promise automatically. Make your API call inside a try-catch block. On success, navigate to the next screen or show a success message. On failure, use setError to show a field-level error or display a general error with Alert.

async function onSubmit(data: RegisterForm) {
  try {
    await api.register({
      email: data.email,
      password: data.password,
      name: data.name,
    });
    navigation.replace('Home');
  } catch (err: any) {
    if (err.status === 409) {
      setError('email', { message: 'This email is already in use.' });
    } else {
      Alert.alert('Registration Failed', 'Please try again later.');
    }
  }
}

isSubmitting to Block Double Submissions

formState.isSubmitting is automatically set to true while your async submit handler is running and to false when it completes. Use it to disable the submit button during the API call. Without this guard, fast double-taps can submit the form twice, causing duplicate records on the server or charging a user twice.

const { handleSubmit, formState: { isSubmitting } } = useForm<LoginForm>();

return (
  <View>
    {/* ... form fields ... */}
    <TouchableOpacity
      onPress={handleSubmit(onSubmit)}
      disabled={isSubmitting}
      style={[styles.button, isSubmitting && styles.buttonDisabled]}
    >
      {isSubmitting
        ? <ActivityIndicator color='white' />
        : <Text style={styles.buttonText}>Log In</Text>
      }
    </TouchableOpacity>
  </View>
);

Handling Submission Errors from the Server

When the server returns a general error (not tied to a specific field), display it near the submit button or in an error banner above the form. Use a local serverError state variable that you set in the catch block. This separates server-level errors from field-level validation errors and gives users a clear message about what went wrong.

const [serverError, setServerError] = React.useState<string | null>(null);

async function onSubmit(data: LoginForm) {
  setServerError(null); // clear previous error
  try {
    await api.login(data);
    navigation.replace('Dashboard');
  } catch {
    setServerError('Login failed. Please check your credentials.');
  }
}

// In render:
{serverError && (
  <Text style={styles.serverError}>{serverError}</Text>
)}

Showing a Success State

After a successful submission, provide clear feedback before navigating away. An inline success message, a check-mark animation, or a brief delay before navigation all help users feel confident the action completed. For forms like contact or feedback submission that do not navigate away, reset the form and show a success banner in place of the submit button.

const [submitted, setSubmitted] = React.useState(false);

async function onSubmit(data: FeedbackForm) {
  await api.sendFeedback(data);
  setSubmitted(true);
  reset();
}

if (submitted) {
  return (
    <View style={styles.success}>
      <Ionicons name='checkmark-circle' size={64} color='green' />
      <Text>Thank you! Your feedback was sent.</Text>
    </View>
  );
}

Resetting to Default Values

Call reset() with no arguments to clear all fields back to their defaultValues and also clear all errors. This is useful for 'Send Another' flows where the user wants to submit the same form type multiple times, or for forms that appear in a modal and need to be blank when reopened. The reset is synchronous and immediate.

const { reset } = useForm<ContactForm>({
  defaultValues: { name: '', email: '', message: '' },
});

async function onSubmit(data: ContactForm) {
  await api.sendMessage(data);
  reset(); // all fields cleared, errors cleared
  Alert.alert('Sent!', 'Your message has been delivered.');
}

Resetting to New Values

Pass a value object to reset(newValues) to replace the default values and repopulate the form at the same time. This is the correct way to pre-fill an edit form with data loaded from the server. Call reset inside a useEffect that runs when the server data arrives to populate all fields without triggering field-level validation.

const { reset } = useForm<ProfileForm>();

useEffect(() => {
  if (userProfile) {
    reset({
      name: userProfile.name,
      bio: userProfile.bio,
      website: userProfile.website ?? '',
    });
  }
}, [userProfile, reset]);

Resetting Individual Fields with setValue

Sometimes you only want to reset or update one specific field without clearing the entire form. Use setValue(fieldName, newValue) for targeted updates. An optional third argument { shouldValidate: true } re-runs validation for that field after the value is set, useful when you programmatically change a field and want errors to update immediately.

const { setValue } = useForm<AddressForm>();

async function handleLocationPress() {
  const loc = await Location.getCurrentPositionAsync({});
  const [address] = await Location.reverseGeocodeAsync(loc.coords);
  setValue('city', address.city ?? '', { shouldValidate: true });
  setValue('postalCode', address.postalCode ?? '');
}

isDirty and Unsaved Changes Guard

formState.isDirty is true when any field value differs from its default value. Use this to warn the user before they navigate away from an unsaved form. Hook into navigation's beforeRemove event (React Navigation) to show a 'Discard changes?' alert when the form is dirty and the user tries to go back.

const { formState: { isDirty } } = form;

useEffect(() => {
  const unsubscribe = navigation.addListener('beforeRemove', (e) => {
    if (!isDirty) return;
    e.preventDefault();
    Alert.alert('Discard changes?', 'You have unsaved changes.', [
      { text: 'Keep Editing', style: 'cancel' },
      { text: 'Discard', style: 'destructive',
        onPress: () => navigation.dispatch(e.data.action) },
    ]);
  });
  return unsubscribe;
}, [navigation, isDirty]);

Validating on Demand with trigger

You can call trigger() with no arguments to validate all fields at any time — not just on submit. Call it when the user taps a 'Check' button, when they reach the end of a scrollable form, or to pre-validate before switching tabs. This is useful for showing all errors at once so users can fix everything before hitting the submit button.

const { trigger, formState: { errors } } = useForm<RegisterForm>();

async function handleCheckAll() {
  const isValid = await trigger();
  if (!isValid) {
    Alert.alert('Please fix the highlighted fields before submitting.');
  }
}

Complete Login Form Example

Here is a production-ready login form combining everything from this lesson: typed useForm, Controller-wrapped inputs, validation rules, isSubmitting guard, server error display, and navigation on success. This template can be adapted for any authentication or data entry screen in a React Native app.

export default function LoginScreen() {
  const { control, handleSubmit, formState: { errors, isSubmitting } } = useForm<LoginForm>();
  const [serverError, setServerError] = React.useState<string | null>(null);

  async function onSubmit(data: LoginForm) {
    setServerError(null);
    try {
      await authApi.login(data.email, data.password);
      navigation.replace('Home');
    } catch { setServerError('Invalid credentials.'); }
  }

  return (
    <View style={styles.container}>
      {serverError && <Text style={styles.serverError}>{serverError}</Text>}
      <EmailController control={control} error={errors.email} />
      <PasswordController control={control} error={errors.password} />
      <Button title={isSubmitting ? 'Logging in...' : 'Log In'}
        onPress={handleSubmit(onSubmit)} disabled={isSubmitting} />
    </View>
  );
}

Quick Check

Test your understanding of React Native Mobile Development concepts from this lesson.

Lesson Recap

In this lesson you learned: handleSubmit validates all fields before calling your async handler and sets isSubmitting automatically, reset() clears the form while reset(newValues) repopulates it for edit scenarios, and isDirty guards against accidental data loss by warning before navigation. Next we begin the B2 courses, starting with Supabase integration in React Native.

자주 묻는 질문

“양식 제출 및 초기화” 강의는 무료인가요?

네 — “양식 제출 및 초기화” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 React Native Academy 강의 전체를 잠금 해제할 수 있습니다. React Native Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“양식 제출 및 초기화”에서 뭘 배우나요?

handleSubmit으로 양식 제출을 처리하고, 검증된 값으로 API를 호출하며, 성공 또는 서버 측 오류 메시지를 표시한 뒤 성공하면 양식을 초기화합니다. 브라우저에서 직접 실행하는 실습 코드로 React Native Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

React Native Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 React Native Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“양식 제출 및 초기화” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 React Native Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 React Native Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. Controller로 react-hook-form 설정하기
  2. 검증 규칙과 오류 메시지
  3. 양식 상태를 활용한 다단계 양식
  4. 양식 제출 및 초기화
← React Native Academy(으)로 돌아가기