إدارة الحالة المتقدمة — React Native المتقدم
إدارة الحالة المتقدمة
1. Zustand (الأسهل والأفضل)
npm install zustand
// stores/useAuthStore.js
import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';
import AsyncStorage from '@react-native-async-storage/async-storage';
const useAuthStore = create(
persist(
(set, get) => ({
user: null,
token: null,
isLoading: false,
login: async (email, password) => {
set({ isLoading: true });
try {
const response = await api.post('/login', { email, password });
set({
user: response.user,
token: response.token,
isLoading: false,
});
return { success: true };
} catch (error) {
set({ isLoading: false });
return { success: false, error: error.message };
}
},
logout: () => {
set({ user: null, token: null });
},
updateUser: (updates) => {
set((state) => ({
user: { ...state.user, ...updates },
}));
},
// Selector
isLoggedIn: () => get().token !== null,
}),
{
name: 'auth-storage',
storage: createJSONStorage(() => AsyncStorage),
}
)
);
// الاستخدام
function ProfileScreen() {
const { user, logout, updateUser } = useAuthStore();
const isLoggedIn = useAuthStore((state) => state.isLoggedIn());
return (
<View>
<Text>مرحباً {user?.name}</Text>
<TouchableOpacity onPress={logout}>
<Text>تسجيل خروج</Text>
</TouchableOpacity>
</View>
);
}
2. متجر للعربة (Cart Store)
// stores/useCartStore.js
import { create } from 'zustand';
const useCartStore = create((set, get) => ({
items: [],
addItem: (product) => {
const items = get().items;
const existingItem = items.find((i) => i.id === product.id);
if (existingItem) {
set({
items: items.map((i) =>
i.id === product.id ? { ...i, quantity: i.quantity + 1 } : i
),
});
} else {
set({ items: [...items, { ...product, quantity: 1 }] });
}
},
removeItem: (productId) => {
set({
items: get().items.filter((i) => i.id !== productId),
});
},
updateQuantity: (productId, quantity) => {
if (quantity <= 0) {
get().removeItem(productId);
return;
}
set({
items: get().items.map((i) =>
i.id === productId ? { ...i, quantity } : i
),
});
},
clearCart: () => set({ items: [] }),
// Computed values
get totalItems() {
return get().items.reduce((sum, item) => sum + item.quantity, 0);
},
get totalPrice() {
return get().items.reduce(
(sum, item) => sum + item.price * item.quantity,
0
);
},
}));
// الاستخدام
function CartScreen() {
const { items, removeItem, updateQuantity, totalPrice } = useCartStore();
return (
<FlatList
data={items}
renderItem={({ item }) => (
<View style={styles.cartItem}>
<Text>{item.name}</Text>
<Text>{item.price} د.ع</Text>
<View style={styles.quantityControls}>
<TouchableOpacity
onPress={() => updateQuantity(item.id, item.quantity - 1)}
>
<Text>-</Text>
</TouchableOpacity>
<Text>{item.quantity}</Text>
<TouchableOpacity
onPress={() => updateQuantity(item.id, item.quantity + 1)}
>
<Text>+</Text>
</TouchableOpacity>
</View>
</View>
)}
ListFooterComponent={
<Text style={styles.total}>المجموع: {totalPrice} د.ع</Text>
}
/>
);
}
// في Header
function CartIcon() {
const totalItems = useCartStore((state) => state.totalItems);
return (
<View>
<Ionicons name="cart" size={24} />
{totalItems > 0 && (
<View style={styles.badge}>
<Text style={styles.badgeText}>{totalItems}</Text>
</View>
)}
</View>
);
}
3. Redux Toolkit (للمشاريع الكبيرة جداً)
npm install @reduxjs/toolkit react-redux
// store/slices/userSlice.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
export const fetchUser = createAsyncThunk(
'user/fetchUser',
async (userId) => {
const response = await api.get(`/users/${userId}`);
return response.data;
}
);
const userSlice = createSlice({
name: 'user',
initialState: {
data: null,
status: 'idle',
error: null,
},
reducers: {
setUser: (state, action) => {
state.data = action.payload;
},
clearUser: (state) => {
state.data = null;
},
},
extraReducers: (builder) => {
builder
.addCase(fetchUser.pending, (state) => {
state.status = 'loading';
})
.addCase(fetchUser.fulfilled, (state, action) => {
state.status = 'succeeded';
state.data = action.payload;
})
.addCase(fetchUser.rejected, (state, action) => {
state.status = 'failed';
state.error = action.error.message;
});
},
});
export const { setUser, clearUser } = userSlice.actions;
export default userSlice.reducer;
// store/index.js
import { configureStore } from '@reduxjs/toolkit';
import userReducer from './slices/userSlice';
export const store = configureStore({
reducer: {
user: userReducer,
},
});
// App.js
import { Provider } from 'react-redux';
import { store } from './store';
function App() {
return (
<Provider store={store}>
<Navigation />
</Provider>
);
}
// الاستخدام في شاشة
import { useSelector, useDispatch } from 'react-redux';
import { fetchUser } from './store/slices/userSlice';
function UserProfile() {
const dispatch = useDispatch();
const { data: user, status, error } = useSelector((state) => state.user);
useEffect(() => {
dispatch(fetchUser(1));
}, [dispatch]);
if (status === 'loading') return <ActivityIndicator />;
if (error) return <Text>Error: {error}</Text>;
return <Text>{user?.name}</Text>;
}
اختبر فهمك