React Native / Маягт ба баталгаажуулалт

Маягт ба баталгаажуулалт

Нэвтрэх маягт, бүртгэл, профайл засварлах — апп бараг бүхэнд маягт байдаг. React Native-д маягт бол TextInput компонентуудын цуглуулга бөгөөд илгээхийн өмнө хэрэглэгчийн оруулсан утгыг баталгаажуулах (validate) шаардлагатай. Энэ хичээлд нэвтрэх маягтаас эхлэн бүтэн маягт хийж сурна.

Нэвтрэх маягт (login form)

Энгийн email + нууц үг маягт. Хоёр TextInput, нэг товч.

jsx
import { useState } from "react";
import {
  View,
  Text,
  TextInput,
  TouchableOpacity,
  StyleSheet,
  Alert,
} from "react-native";

export default function LoginForm() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  const handleLogin = () => {
    // Баталгаажуулалт
    if (!email.trim()) {
      Alert.alert("Алдаа", "И-мэйл хаяг оруулна уу");
      return;
    }
    if (!password) {
      Alert.alert("Алдаа", "Нууц үг оруулна уу");
      return;
    }
    if (!email.includes("@")) {
      Alert.alert("Алдаа", "И-мэйл хаяг буруу байна");
      return;
    }
    // Нэвтрэх логик энд...
    Alert.alert("Амжилттай", `${email} хаягаар нэвтэрлээ`);
  };

  return (
    <View style={styles.container}>
      <Text style={styles.heading}>Нэвтрэх</Text>

      <Text style={styles.label}>И-мэйл</Text>
      <TextInput
        style={styles.input}
        value={email}
        onChangeText={setEmail}
        placeholder="name@example.com"
        placeholderTextColor="#475569"
        keyboardType="email-address"
        autoCapitalize="none"
        autoCorrect={false}
      />

      <Text style={styles.label}>Нууц үг</Text>
      <TextInput
        style={styles.input}
        value={password}
        onChangeText={setPassword}
        placeholder="••••••••"
        placeholderTextColor="#475569"
        secureTextEntry
      />

      <TouchableOpacity style={styles.btn} onPress={handleLogin}>
        <Text style={styles.btnText}>Нэвтрэх</Text>
      </TouchableOpacity>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 24,
    backgroundColor: "#0b1120",
    justifyContent: "center",
  },
  heading: {
    fontSize: 26,
    fontWeight: "bold",
    color: "#f1f5f9",
    marginBottom: 32,
  },
  label: {
    color: "#94a3b8",
    fontSize: 13,
    marginBottom: 6,
    fontWeight: "500",
  },
  input: {
    backgroundColor: "#0f172a",
    borderWidth: 1,
    borderColor: "#1e293b",
    borderRadius: 10,
    padding: 14,
    color: "#f1f5f9",
    fontSize: 15,
    marginBottom: 16,
  },
  btn: {
    backgroundColor: "#22d3ee",
    borderRadius: 10,
    padding: 16,
    alignItems: "center",
    marginTop: 8,
  },
  btnText: {
    color: "#0b1120",
    fontWeight: "700",
    fontSize: 16,
  },
});

secureTextEntry нууц үгийг нуудаг. keyboardType="email-address" email гар гарч ирдэг. autoCapitalize="none" автомат том үсэг болгохгүй.

Inline алдааны мэдэгдэл

Alert диалог харуулахын оронд input-н доор шууд алдааны текст харуулах нь илүү сайн UX:

jsx
import { useState } from "react";
import {
  View,
  Text,
  TextInput,
  TouchableOpacity,
  StyleSheet,
} from "react-native";

function validateEmail(email) {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

export default function RegisterForm() {
  const [form, setForm] = useState({ name: "", email: "", password: "" });
  const [errors, setErrors] = useState({});
  const [submitting, setSubmitting] = useState(false);

  const update = (field, value) => {
    setForm((prev) => ({ ...prev, [field]: value }));
    // Хэрэглэгч бичиж эхлэхэд алдааг арилгана
    if (errors[field]) setErrors((prev) => ({ ...prev, [field]: "" }));
  };

  const validate = () => {
    const newErrors = {};
    if (!form.name.trim()) newErrors.name = "Нэр оруулна уу";
    if (!form.email) newErrors.email = "И-мэйл оруулна уу";
    else if (!validateEmail(form.email)) newErrors.email = "И-мэйл буруу байна";
    if (form.password.length < 6)
      newErrors.password = "Нууц үг хамгийн багадаа 6 тэмдэгт байх ёстой";
    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  };

  const handleSubmit = async () => {
    if (!validate()) return;
    setSubmitting(true);
    await new Promise((r) => setTimeout(r, 1000)); // API дуудлага
    setSubmitting(false);
  };

  const Field = ({ label, field, ...props }) => (
    <View style={styles.fieldWrap}>
      <Text style={styles.label}>{label}</Text>
      <TextInput
        style={[styles.input, errors[field] && styles.inputError]}
        value={form[field]}
        onChangeText={(val) => update(field, val)}
        placeholderTextColor="#475569"
        {...props}
      />
      {errors[field] ? (
        <Text style={styles.errorText}>{errors[field]}</Text>
      ) : null}
    </View>
  );

  return (
    <View style={styles.container}>
      <Text style={styles.heading}>Бүртгүүлэх</Text>

      <Field label="Нэр" field="name" placeholder="Дорж Бат" />
      <Field
        label="И-мэйл"
        field="email"
        placeholder="name@example.com"
        keyboardType="email-address"
        autoCapitalize="none"
      />
      <Field
        label="Нууц үг"
        field="password"
        placeholder="хамгийн багадаа 6 тэмдэгт"
        secureTextEntry
      />

      <TouchableOpacity
        style={[styles.btn, submitting && styles.btnDisabled]}
        onPress={handleSubmit}
        disabled={submitting}
      >
        <Text style={styles.btnText}>
          {submitting ? "Хадгалж байна..." : "Бүртгүүлэх"}
        </Text>
      </TouchableOpacity>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 24,
    backgroundColor: "#0b1120",
    justifyContent: "center",
  },
  heading: {
    fontSize: 26,
    fontWeight: "bold",
    color: "#f1f5f9",
    marginBottom: 28,
  },
  fieldWrap: {
    marginBottom: 16,
  },
  label: {
    color: "#94a3b8",
    fontSize: 13,
    marginBottom: 6,
    fontWeight: "500",
  },
  input: {
    backgroundColor: "#0f172a",
    borderWidth: 1,
    borderColor: "#1e293b",
    borderRadius: 10,
    padding: 14,
    color: "#f1f5f9",
    fontSize: 15,
  },
  inputError: {
    borderColor: "#fb7185",
  },
  errorText: {
    color: "#fb7185",
    fontSize: 12,
    marginTop: 4,
  },
  btn: {
    backgroundColor: "#22d3ee",
    borderRadius: 10,
    padding: 16,
    alignItems: "center",
    marginTop: 12,
  },
  btnDisabled: {
    opacity: 0.5,
  },
  btnText: {
    color: "#0b1120",
    fontWeight: "700",
    fontSize: 16,
  },
});

KeyboardAvoidingView — гар дэлгэцийг битгий хааг

Гар нээгдэх үед input-г нуудаг. KeyboardAvoidingView ашиглан дэлгэцийг дээш шилжүүлнэ:

jsx
import { KeyboardAvoidingView, Platform, ScrollView } from "react-native";

export default function FormScreen() {
  return (
    <KeyboardAvoidingView
      style={{ flex: 1, backgroundColor: "#0b1120" }}
      behavior={Platform.OS === "ios" ? "padding" : "height"}
    >
      <ScrollView
        keyboardShouldPersistTaps="handled"
        contentContainerStyle={{ padding: 24, paddingTop: 60 }}
      >
        {/* Маягтын агуулга энд */}
      </ScrollView>
    </KeyboardAvoidingView>
  );
}

Platform.OS === 'ios' iOS болон Android-д өөр өөр behavior шаардлагатай тул шалгана. keyboardShouldPersistTaps="handled" гараас гадна дарахад гар хаагдана.

Маягт зөв хийхэд хэрэглэгч цочирдохгүй — баталгаажуулалтыг дэлгэцэн дээр inline харуулах, гар маягтыг бүрхэхгүй байх хоёр дүрмийг дагавал таны маягт мэргэжлийн болно.

Дараагийн хичээлд:

Expo Camera — утасны камераа ашиглаж зураг авах, урд/арын камер сэлгэх функц сурна.