React Native / useState React Native-д

useState React Native-д

React курст useState-г сурсан байгаа — React Native-д яг адилхан ажилладаг. Ялгаа нь зөвхөн <div> биш <View>, <button> биш <TouchableOpacity> ашиглах явдал. Энэ хичээлд мобайл UI-д хамгийн их тохиолддог useState загваруудыг нэгтгэн давтана.

Counter — үндсэн useState

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

export default function Counter() {
  const [count, setCount] = useState(0);

  return (
    <View style={styles.container}>
      <Text style={styles.count}>{count}</Text>
      <Text style={styles.label}>XP</Text>

      <View style={styles.row}>
        <TouchableOpacity
          style={[styles.btn, styles.minus]}
          onPress={() => setCount((c) => Math.max(0, c - 1))}
        >
          <Text style={styles.btnText}></Text>
        </TouchableOpacity>

        <TouchableOpacity
          style={[styles.btn, styles.plus]}
          onPress={() => setCount((c) => c + 1)}
        >
          <Text style={styles.btnText}>+</Text>
        </TouchableOpacity>
      </View>

      <TouchableOpacity onPress={() => setCount(0)}>
        <Text style={styles.reset}>Дахин тохируулах</Text>
      </TouchableOpacity>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: "#0b1120",
    gap: 12,
  },
  count: { fontSize: 72, fontWeight: "bold", color: "#22d3ee" },
  label: { fontSize: 16, color: "#475569", marginTop: -8 },
  row: { flexDirection: "row", gap: 16, marginTop: 8 },
  btn: {
    width: 56,
    height: 56,
    borderRadius: 28,
    justifyContent: "center",
    alignItems: "center",
  },
  minus: { backgroundColor: "#1e293b" },
  plus: { backgroundColor: "#22d3ee" },
  btnText: { fontSize: 24, color: "#f1f5f9", fontWeight: "bold" },
  reset: { fontSize: 14, color: "#334155", marginTop: 8 },
});

setCount((c) => c + 1) — функц хэлбэрийн шинэчлэлт нь өмнөх утгад тулгуурлан тооцоход найдвартай. Ялангуяа товчийг хурдан дарахад алдаа гарахаас сэргийлдэг.

Toggle — нэмэх/хасах төлөв

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

export default function ToggleList() {
  const [darkMode, setDarkMode] = useState(true);
  const [notifications, setNotifications] = useState(false);
  const [expanded, setExpanded] = useState(false);

  return (
    <View style={[styles.container, !darkMode && styles.lightBg]}>
      {/* Switch toggle */}
      <View style={styles.row}>
        <Text style={styles.label}>Харанхуй горим</Text>
        <Switch
          value={darkMode}
          onValueChange={setDarkMode}
          trackColor={{ false: "#1e293b", true: "#164e63" }}
          thumbColor={darkMode ? "#22d3ee" : "#475569"}
        />
      </View>

      <View style={styles.row}>
        <Text style={styles.label}>Мэдэгдэл</Text>
        <Switch
          value={notifications}
          onValueChange={setNotifications}
          trackColor={{ false: "#1e293b", true: "#164e63" }}
          thumbColor={notifications ? "#22d3ee" : "#475569"}
        />
      </View>

      {/* Accordion toggle */}
      <TouchableOpacity
        style={styles.accordion}
        onPress={() => setExpanded((e) => !e)}
      >
        <Text style={styles.label}>Дэлгэрэнгүй мэдээлэл</Text>
        <Text style={styles.chevron}>{expanded ? "∧" : "∨"}</Text>
      </TouchableOpacity>
      {expanded && (
        <View style={styles.panel}>
          <Text style={styles.panelText}>
            Энэ хэсэг accordion дарахад нээгдэж, дахин дарахад хаагдана.
          </Text>
        </View>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, padding: 20, backgroundColor: "#0b1120" },
  lightBg: { backgroundColor: "#f8fafc" },
  row: {
    flexDirection: "row",
    justifyContent: "space-between",
    alignItems: "center",
    backgroundColor: "#0f172a",
    padding: 16,
    borderRadius: 10,
    marginBottom: 10,
  },
  label: { fontSize: 15, color: "#f1f5f9" },
  chevron: { fontSize: 14, color: "#475569" },
  accordion: {
    flexDirection: "row",
    justifyContent: "space-between",
    alignItems: "center",
    backgroundColor: "#0f172a",
    padding: 16,
    borderRadius: 10,
  },
  panel: {
    backgroundColor: "#1e293b",
    padding: 16,
    borderRadius: 10,
    marginTop: 2,
  },
  panelText: { color: "#94a3b8", fontSize: 14, lineHeight: 22 },
});

Олон state нэг объектод хадгалах

Маягтны талбаруудын утгыг тус тусдаа useState -ээр хадгалах боломжтой. Гэхдээ хамааралтай өгөгдлийг нэг объектод нэгтгэх нь код уншихад ойлгомжтой болгодог:

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

export default function RegisterForm() {
  const [form, setForm] = useState({
    username: "",
    email: "",
    password: "",
  });

  // Нэг функцээр аль ч талбарыг шинэчилнэ
  const update = (field, value) =>
    setForm((prev) => ({ ...prev, [field]: value }));

  const isValid =
    form.username.length > 2 &&
    form.email.includes("@") &&
    form.password.length >= 6;

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

      <TextInput
        style={styles.input}
        value={form.username}
        onChangeText={(v) => update("username", v)}
        placeholder="Хэрэглэгчийн нэр"
        placeholderTextColor="#475569"
      />
      <TextInput
        style={styles.input}
        value={form.email}
        onChangeText={(v) => update("email", v)}
        placeholder="И-мэйл"
        placeholderTextColor="#475569"
        keyboardType="email-address"
        autoCapitalize="none"
      />
      <TextInput
        style={styles.input}
        value={form.password}
        onChangeText={(v) => update("password", v)}
        placeholder="Нууц үг (6+ тэмдэгт)"
        placeholderTextColor="#475569"
        secureTextEntry
      />

      <TouchableOpacity
        style={[styles.btn, !isValid && styles.btnDisabled]}
        disabled={!isValid}
      >
        <Text style={styles.btnText}>Бүртгүүлэх</Text>
      </TouchableOpacity>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    padding: 24,
    backgroundColor: "#0b1120",
  },
  title: {
    fontSize: 26,
    fontWeight: "bold",
    color: "#f1f5f9",
    marginBottom: 24,
  },
  input: {
    backgroundColor: "#0f172a",
    borderWidth: 1,
    borderColor: "#1e293b",
    borderRadius: 8,
    padding: 13,
    color: "#f1f5f9",
    fontSize: 15,
    marginBottom: 12,
  },
  btn: {
    backgroundColor: "#22d3ee",
    padding: 14,
    borderRadius: 10,
    alignItems: "center",
    marginTop: 8,
  },
  btnDisabled: { opacity: 0.4 },
  btnText: { color: "#0b1120", fontWeight: "bold", fontSize: 16 },
});

{ ...prev, [field]: value } нь spread оператор ашиглан өмнөх бүх талбарыг хадгалж зөвхөн тодорхой нэгийг нь шинэчилдэг. isValid нь бүх талбарын утгыг шалгаж товчийг идэвхтэй эсэхийг тодорхойлно.

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

useState-ийн мобайл загваруудыг нэгтгэн давтлаа. Дараагийн хичээлд useEffect React Native-д — апп нээгдэх үед өгөгдөл татах, дэлгэц өөрчлөгдөхөд ажиллах side effect-үүдийг удирдана.