React Native / Zustand React Native-д

Zustand React Native-д

Zustand бол маш хялбар, боловч хүчирхэг state менежментийн сан. Context API-тай харьцуулбал бичих код хамаагүй бага, гүйцэтгэл сайн, Provider дотор ороодог хэрэггүй. React Native-д Context-н оронд Zustand ашиглах нь улам түгэмжилж байна.

Суулгалт

bash
npm install zustand

Анхны store үүсгэх

Zustand-д create() функцээр store үүсгэнэ. Store нь state болон тэр state-г өөрчлөх функцуудыг хамт агуулдаг:

jsx
// store/useCounterStore.js
import { create } from "zustand";

const useCounterStore = create((set) => ({
  // State
  count: 0,
  // Actions
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: Math.max(0, state.count - 1) })),
  reset: () => set({ count: 0 }),
}));

export default useCounterStore;

set функц state-г шинэчилдэг. Өмнөх state-д тулгуурлах үед set((state) => ...) функц хэлбэрийг ашиглана.

Component-д ашиглах

Provider шаардлагагүй — store-г шууд import хийгээд hook шиг дуудана:

jsx
import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
import useCounterStore from "../store/useCounterStore";

export default function CounterScreen() {
  const { count, increment, decrement, reset } = useCounterStore();

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

      <View style={styles.row}>
        <TouchableOpacity
          style={[styles.btn, styles.secondary]}
          onPress={decrement}
        >
          <Text style={styles.btnText}></Text>
        </TouchableOpacity>
        <TouchableOpacity
          style={[styles.btn, styles.primary]}
          onPress={increment}
        >
          <Text style={styles.btnText}>+</Text>
        </TouchableOpacity>
      </View>

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

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: "#0b1120",
    gap: 20,
  },
  count: { fontSize: 72, fontWeight: "bold", color: "#22d3ee" },
  row: { flexDirection: "row", gap: 16 },
  btn: {
    width: 60,
    height: 60,
    borderRadius: 30,
    justifyContent: "center",
    alignItems: "center",
  },
  primary: { backgroundColor: "#22d3ee" },
  secondary: { backgroundColor: "#1e293b" },
  btnText: { fontSize: 28, color: "#0b1120", fontWeight: "bold" },
  reset: { fontSize: 14, color: "#334155" },
});

Өөр дэлгэцэд ч useCounterStore() дуудахад ижил count утга харагдана — store нь глобал.

Бодит жишээ: хэрэглэгчийн XP store

jsx
// store/useUserStore.js
import { create } from "zustand";

const useUserStore = create((set, get) => ({
  user: null,
  completedLessons: [],

  setUser: (userData) => set({ user: userData }),

  logout: () => set({ user: null, completedLessons: [] }),

  completeLesson: (slug) => {
    const { completedLessons, user } = get();
    if (completedLessons.includes(slug)) return; // Давтаж нэмэхгүй

    set({
      completedLessons: [...completedLessons, slug],
      user: user ? { ...user, xp: user.xp + 10 } : user,
    });
  },

  isCompleted: (slug) => get().completedLessons.includes(slug),
}));

export default useUserStore;

get() нь store-н одоогийн утгыг action дотроос унших боломж олгодог — set нь зөвхөн бичихэд, get нь зөвхөн уншихад ашиглана.

jsx
// screens/LessonScreen.jsx
import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
import useUserStore from "../store/useUserStore";

export default function LessonScreen({ route }) {
  const { slug, title } = route.params;
  const { user, completeLesson, isCompleted } = useUserStore();
  const done = isCompleted(slug);

  return (
    <View style={styles.container}>
      <Text style={styles.title}>{title}</Text>
      <Text style={styles.xp}>Таны XP: {user?.xp ?? 0}</Text>

      <TouchableOpacity
        style={[styles.btn, done && styles.btnDone]}
        onPress={() => completeLesson(slug)}
        disabled={done}
      >
        <Text style={styles.btnText}>
          {done ? "✓ Дууссан — +10 XP" : "Дуусгах"}
        </Text>
      </TouchableOpacity>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    padding: 24,
    backgroundColor: "#0b1120",
  },
  title: {
    fontSize: 22,
    fontWeight: "bold",
    color: "#f1f5f9",
    marginBottom: 8,
  },
  xp: { fontSize: 15, color: "#22d3ee", marginBottom: 32 },
  btn: {
    backgroundColor: "#22d3ee",
    padding: 14,
    borderRadius: 10,
    alignItems: "center",
  },
  btnDone: { backgroundColor: "#1e293b" },
  btnText: { color: "#0b1120", fontWeight: "bold", fontSize: 15 },
});

Context API ба Zustand харьцуулбал

| | Context API | Zustand | | ----------- | ------------------- | ----------------------------- | | Суулгалт | Суулгахгүй | npm install zustand | | Provider | Шаардлагатай | Шаардлагагүй | | Бичих код | Арай их | Маш бага | | Гүйцэтгэл | Дундаж | Өндөр | | Хэрэглэх үе | Энгийн глобал state | Том апп, ойр ойрхон шинэчлэлт |

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

Zustand store бүтээж сурлаа. Дараагийн хичээлд Fetch API ба өгөгдөл татах — серверээс жинхэнэ өгөгдөл татах, loading/error төлөвүүдийг зохистой удирдах бүрэн загварыг судална.