Browse Source

zustand initialized

MGTKenYCS 1 năm trước cách đây
mục cha
commit
66c47fb69c

+ 0 - 32
App.tsx

@@ -1,32 +0,0 @@
-import { StatusBar } from "expo-status-bar";
-import { StyleSheet, Text, View } from "react-native";
-import { Provider } from "react-redux";
-import Counter from "./component/counter";
-import store from "./store";
-
-const styles = StyleSheet.create({
-  container: {
-    flex: 1,
-    backgroundColor: "#fff",
-    alignItems: "center",
-    justifyContent: "center",
-  },
-});
-
-function App() {
-  return (
-    <View style={styles.container}>
-      <Text>Open up App.tsx to start working on your app!</Text>
-      <StatusBar style="auto" />
-      <Counter />
-    </View>
-  );
-}
-
-export default function Root() {
-  return (
-    <Provider store={store}>
-      <App />
-    </Provider>
-  );
-}

+ 29 - 43
app/(tabs)/index.tsx

@@ -1,26 +1,14 @@
-import React, { useEffect, useState } from "react";
-import { Text, StyleSheet, View, PermissionsAndroid } from "react-native";
-import MapView, { Marker } from "react-native-maps";
-import * as Location from "expo-location";
-import { LocationObject } from "expo-location";
-import { mapStyle } from "../../style/map";
+import React from "react";
+import { StyleSheet, View, Text, Pressable } from "react-native";
+import useTestStore from "../../providers/test_store";
+import useSignUpStore from "../../providers/signup_form_store";
 
 export default function Index() {
   /**********************************狀態管理**********************************/
-  const [location, setLocation] = useState<LocationObject>();
+  const value = useTestStore((state) => state.value);
+  const add = useTestStore((state) => state.add);
+  const minus = useTestStore((state) => state.minus);
 
-  useEffect(() => {
-    (async () => {
-      let { status } = await Location.requestForegroundPermissionsAsync();
-      if (status !== "granted") {
-        console.log("Permission denied");
-        return;
-      }
-
-      let location = await Location.getCurrentPositionAsync({});
-      setLocation(location);
-    })();
-  }, []);
   /**********************************狀態管理**********************************/
   /**********************************組件初始化**********************************/
   /**********************************組件初始化**********************************/
@@ -28,33 +16,31 @@ export default function Index() {
   /**********************************異步函數**********************************/
   return (
     <View>
-      {location && (
-        <MapView
-          customMapStyle={mapStyle}
-          followsUserLocation={true}
-          initialRegion={{
-            latitude: 22.3193,
-            longitude: 114.1694,
-            latitudeDelta: 0.1,
-            longitudeDelta: 0.1,
-          }}
-          showsPointsOfInterest={false}
-          showsUserLocation={true}
-          showsBuildings={false}
-          showsTraffic={false}
-          style={styles.map}
-        >
-          <Marker
-            coordinate={{ latitude: 22.3193, longitude: 114.1694 }}
-            title="Marker Title"
-            onPress={() => {}}
-            description="Marker Description"
-          />
-        </MapView>
-      )}
+      <TestButton cb={minus} label="Minus" />
+      <Text>States goes here: {value}</Text>
+      <TestButton cb={add} label="Add" />
     </View>
   );
 }
+
+const TestButton = ({ label, cb }: { label: string; cb: () => void }) => (
+  <Pressable
+    onPress={() => {
+      cb();
+    }}
+  >
+    <Text
+      style={{
+        color: "#02677D",
+        fontSize: 16,
+        paddingVertical: 5,
+      }}
+    >
+      {label}
+    </Text>
+  </Pressable>
+);
+
 const styles = StyleSheet.create({
   container: {
     flex: 1,

+ 0 - 25
component/counter.tsx

@@ -1,25 +0,0 @@
-import React from "react";
-import { useSelector, useDispatch } from "react-redux";
-import { counterSlice, decrement, increment } from "../reducers/counterReducer";
-import { Button, Text, View } from "react-native";
-import store from "../store";
-
-export default function Counter() {
-  /**********************************狀態管理**********************************/
-  const value = useSelector((state: any) => state.counter.value);
-  const dispatch = useDispatch();
-  /**********************************狀態管理**********************************/
-  /**********************************組件初始化**********************************/
-  /**********************************組件初始化**********************************/
-  /**********************************異步函數**********************************/
-  /**********************************異步函數**********************************/
-  return (
-    <View>
-      <View style={{ flexDirection: "row", alignItems: "center" }}>
-        <Button title="Increment" onPress={() => dispatch(increment())} />
-        <Text>{value}</Text>
-        <Button title="Decrement" onPress={() => dispatch(decrement())} />
-      </View>
-    </View>
-  );
-}

+ 2 - 2
component/global/phone_input.tsx

@@ -1,10 +1,10 @@
 import React, { useState } from "react";
 import { View, Text, TextInput, StyleSheet, ViewStyle, StyleProp } from "react-native";
-import { HandleFormDataChange } from "../type";
+import { HandleSignUpFormDataChange } from "../../types/signup";
 interface PhoneInputProps {
 	placeholder: string;
 	extendedStyle?: StyleProp<ViewStyle>;
-	handleFormDataChange?: HandleFormDataChange;
+	handleFormDataChange?: HandleSignUpFormDataChange;
 	editable?: boolean;
 }
 

+ 4 - 4
component/multiStepForm/formComponent/form.tsx

@@ -5,15 +5,15 @@ import BasicInformation from "./formPages/basicInformation";
 import UberDriver from "./formPages/uberDriver";
 import CarInformation from "./formPages/carInformation";
 import PaginationIndicator from "../../global/PaginationIndicator";
-import { FormData, FormDataKey } from "../../type";
+import { SignUpFormData, SignUpFormDataKey } from "../../../types/signup";
 import CreateWallet from "./formPages/createWallet";
 import FinishSignUp from "./formPages/finishSignUp";
 import LoginPage from "./formPages/loginPage";
 import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view";
 
 type FormProps = {
-	formData: FormData;
-	setFormData: React.Dispatch<React.SetStateAction<FormData>>;
+	formData: SignUpFormData;
+	setFormData: React.Dispatch<React.SetStateAction<SignUpFormData>>;
 };
 const Form: React.FC<FormProps> = ({ formData, setFormData }) => {
 	const [screen, setScreen] = useState<number>(0);
@@ -26,7 +26,7 @@ const Form: React.FC<FormProps> = ({ formData, setFormData }) => {
 		"註冊 - 設立銀包",
 	];
 
-	const handleFormDataChange = <K extends FormDataKey>(field: K, value: FormData[K]) => {
+	const handleFormDataChange = <K extends SignUpFormDataKey>(field: K, value: SignUpFormData[K]) => {
 		setFormData((prevFormData) => ({
 			...prevFormData,
 			[field]: value,

+ 3 - 3
component/multiStepForm/formComponent/formPages/basicInformation.tsx

@@ -3,12 +3,12 @@ import NormalInput from "../../../global/normal_input";
 import { useState } from "react";
 import DateModal from "../../../global/date_input";
 import NormalButton from "../../../global/normal_button";
-import { FormData, HandleFormDataChange } from "../../../type";
+import { SignUpFormData, HandleSignUpFormDataChange } from "../../../../types/signup";
 
 type basicInformationProps = {
 	goToNextPage: () => void;
-	handleFormDataChange: HandleFormDataChange;
-	formData: FormData;
+	handleFormDataChange: HandleSignUpFormDataChange;
+	formData: SignUpFormData;
 };
 
 const BasicInformation: React.FC<basicInformationProps> = ({ handleFormDataChange, goToNextPage, formData }) => {

+ 3 - 3
component/multiStepForm/formComponent/formPages/carInformation.tsx

@@ -1,13 +1,13 @@
 import { View, Text, StyleSheet } from "react-native";
-import { FormData, HandleFormDataChange } from "../../../type";
+import { SignUpFormData, HandleSignUpFormDataChange } from "../../../../types/signup";
 import NormalInput from "../../../global/normal_input";
 import NormalButton from "../../../global/normal_button";
 import { useState } from "react";
 
 type CarInformationProps = {
 	goToNextPage: () => void;
-	handleFormDataChange: HandleFormDataChange;
-	formData: FormData;
+	handleFormDataChange: HandleSignUpFormDataChange;
+	formData: SignUpFormData;
 };
 
 const CarInformation: React.FC<CarInformationProps> = ({ goToNextPage, handleFormDataChange, formData }) => {

+ 3 - 3
component/multiStepForm/formComponent/formPages/createWallet.tsx

@@ -1,5 +1,5 @@
 import { View, Text, StyleSheet } from "react-native";
-import { FormData, HandleFormDataChange } from "../../../type";
+import { SignUpFormData, HandleSignUpFormDataChange } from "../../../../types/signup";
 import NormalInput from "../../../global/normal_input";
 import NormalButton from "../../../global/normal_button";
 import { useState } from "react";
@@ -7,8 +7,8 @@ import SingleSelectButtonGroup from "../../../global/select_button";
 
 type CreateWalletProps = {
 	goToNextPage: () => void;
-	handleFormDataChange: HandleFormDataChange;
-	formData: FormData;
+	handleFormDataChange: HandleSignUpFormDataChange;
+	formData: SignUpFormData;
 };
 const creditCard = "信用卡";
 const weChatAliPay = "微信支付/支付寶";

+ 3 - 3
component/multiStepForm/formComponent/formPages/uberDriver.tsx

@@ -1,13 +1,13 @@
 import { View, Text, StyleSheet } from "react-native";
-import { FormData, HandleFormDataChange } from "../../../type";
+import { SignUpFormData, HandleSignUpFormDataChange } from "../../../../types/signup";
 import NormalButton from "../../../global/normal_button";
 import { useState } from "react";
 import SingleSelectButtonGroup from "../../../global/select_button";
 
 type UberDriverProps = {
 	goToNextPage: () => void;
-	handleFormDataChange: HandleFormDataChange;
-	formData: FormData;
+	handleFormDataChange: HandleSignUpFormDataChange;
+	formData: SignUpFormData;
 };
 
 const UberDriver: React.FC<UberDriverProps> = ({ formData, goToNextPage, handleFormDataChange }) => {

+ 3 - 3
component/multiStepForm/formComponent/formPages/verification.tsx

@@ -1,14 +1,14 @@
 import { View, Text, StyleSheet, TextInput, Pressable } from "react-native";
 import { useEffect, useState } from "react";
-import { FormData, HandleFormDataChange } from "../../../type";
+import { SignUpFormData, HandleSignUpFormDataChange } from "../../../../types/signup";
 import PhoneInput from "../../../global/phone_input";
 import NumberInput from "../../../global/number_input";
 import NormalButton from "../../../global/normal_button";
 
 type VerificationProps = {
 	setScreen: React.Dispatch<React.SetStateAction<number>>;
-	formData: FormData;
-	handleFormDataChange: HandleFormDataChange;
+	formData: SignUpFormData;
+	handleFormDataChange: HandleSignUpFormDataChange;
 };
 
 const Verification: React.FC<VerificationProps> = ({ setScreen, formData, handleFormDataChange }) => {

+ 2 - 2
component/multiStepForm/multi_step_form.tsx

@@ -2,10 +2,10 @@ import { Text, View, StyleSheet } from "react-native";
 import { StatusBar } from "expo-status-bar";
 import Form from "./formComponent/form";
 import { useEffect, useState } from "react";
-import { FormData } from "../type";
+import { SignUpFormData } from "../../types/signup";
 
 const MultiStepForm: React.FC = () => {
-	const [formData, setFormData] = useState<FormData>({
+	const [formData, setFormData] = useState<SignUpFormData>({
 		phone: "",
 		phoneVerificationStatus: false,
 		name: "",

+ 66 - 0
component/test/map.tsx

@@ -0,0 +1,66 @@
+import React, { useEffect, useState } from "react";
+import { StyleSheet, View } from "react-native";
+import MapView, { Marker } from "react-native-maps";
+import * as Location from "expo-location";
+import { LocationObject } from "expo-location";
+import { mapStyle } from "../../style/map";
+
+export default function Index() {
+  /**********************************狀態管理**********************************/
+  const [location, setLocation] = useState<LocationObject>();
+
+  useEffect(() => {
+    (async () => {
+      let { status } = await Location.requestForegroundPermissionsAsync();
+      if (status !== "granted") {
+        console.log("Permission denied");
+        return;
+      }
+
+      let location = await Location.getCurrentPositionAsync({});
+      setLocation(location);
+    })();
+  }, []);
+  /**********************************狀態管理**********************************/
+  /**********************************組件初始化**********************************/
+  /**********************************組件初始化**********************************/
+  /**********************************異步函數**********************************/
+  /**********************************異步函數**********************************/
+  return (
+    <View>
+      {location && (
+        <MapView
+          customMapStyle={mapStyle}
+          followsUserLocation={true}
+          initialRegion={{
+            latitude: 22.3193,
+            longitude: 114.1694,
+            latitudeDelta: 0.1,
+            longitudeDelta: 0.1,
+          }}
+          showsPointsOfInterest={false}
+          showsUserLocation={true}
+          showsBuildings={false}
+          showsTraffic={false}
+          style={styles.map}
+        >
+          <Marker
+            coordinate={{ latitude: 22.3193, longitude: 114.1694 }}
+            title="Marker Title"
+            onPress={() => {}}
+            description="Marker Description"
+          />
+        </MapView>
+      )}
+    </View>
+  );
+}
+const styles = StyleSheet.create({
+  container: {
+    flex: 1,
+  },
+  map: {
+    width: "100%",
+    height: "100%",
+  },
+});

+ 28 - 84
package-lock.json

@@ -8,7 +8,6 @@
       "name": "template",
       "version": "1.0.0",
       "dependencies": {
-        "@reduxjs/toolkit": "^2.2.1",
         "@types/react-native-datepicker": "^1.7.6",
         "axios": "^1.6.7",
         "dotenv": "^16.4.5",
@@ -26,8 +25,7 @@
         "react-native-modern-datepicker": "^1.0.0-beta.91",
         "react-native-safe-area-context": "4.10.1",
         "react-native-screens": "3.31.1",
-        "react-redux": "^9.1.0",
-        "redux": "^5.0.1"
+        "zustand": "^4.5.2"
       },
       "devDependencies": {
         "@babel/core": "^7.20.0",
@@ -5953,29 +5951,6 @@
         "nanoid": "^3.1.23"
       }
     },
-    "node_modules/@reduxjs/toolkit": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.1.tgz",
-      "integrity": "sha512-8CREoqJovQW/5I4yvvijm/emUiCCmcs4Ev4XPWd4mizSO+dD3g5G6w34QK5AGeNrSH7qM8Fl66j4vuV7dpOdkw==",
-      "dependencies": {
-        "immer": "^10.0.3",
-        "redux": "^5.0.1",
-        "redux-thunk": "^3.1.0",
-        "reselect": "^5.0.1"
-      },
-      "peerDependencies": {
-        "react": "^16.9.0 || ^17.0.0 || ^18",
-        "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0"
-      },
-      "peerDependenciesMeta": {
-        "react": {
-          "optional": true
-        },
-        "react-redux": {
-          "optional": true
-        }
-      }
-    },
     "node_modules/@remix-run/node": {
       "version": "2.9.2",
       "resolved": "https://registry.npmjs.org/@remix-run/node/-/node-2.9.2.tgz",
@@ -6283,11 +6258,6 @@
       "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz",
       "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw=="
     },
-    "node_modules/@types/use-sync-external-store": {
-      "version": "0.0.3",
-      "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
-      "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
-    },
     "node_modules/@types/yargs": {
       "version": "17.0.32",
       "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz",
@@ -9138,15 +9108,6 @@
         "node": ">=16.x"
       }
     },
-    "node_modules/immer": {
-      "version": "10.0.4",
-      "resolved": "https://registry.npmjs.org/immer/-/immer-10.0.4.tgz",
-      "integrity": "sha512-cuBuGK40P/sk5IzWa9QPUaAdvPHjkk1c+xYsd9oZw+YQQEV+10G0P5uMpGctZZKnyQ+ibRO08bD25nWLmYi2pw==",
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/immer"
-      }
-    },
     "node_modules/import-fresh": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
@@ -12792,32 +12753,6 @@
         "async-limiter": "~1.0.0"
       }
     },
-    "node_modules/react-redux": {
-      "version": "9.1.0",
-      "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.0.tgz",
-      "integrity": "sha512-6qoDzIO+gbrza8h3hjMA9aq4nwVFCKFtY2iLxCtVT38Swyy2C/dJCGBXHeHLtx6qlg/8qzc2MrhOeduf5K32wQ==",
-      "dependencies": {
-        "@types/use-sync-external-store": "^0.0.3",
-        "use-sync-external-store": "^1.0.0"
-      },
-      "peerDependencies": {
-        "@types/react": "^18.2.25",
-        "react": "^18.0",
-        "react-native": ">=0.69",
-        "redux": "^5.0.0"
-      },
-      "peerDependenciesMeta": {
-        "@types/react": {
-          "optional": true
-        },
-        "react-native": {
-          "optional": true
-        },
-        "redux": {
-          "optional": true
-        }
-      }
-    },
     "node_modules/react-refresh": {
       "version": "0.14.2",
       "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
@@ -12890,19 +12825,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/redux": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
-      "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="
-    },
-    "node_modules/redux-thunk": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz",
-      "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
-      "peerDependencies": {
-        "redux": "^5.0.0"
-      }
-    },
     "node_modules/regenerate": {
       "version": "1.4.2",
       "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -13032,11 +12954,6 @@
         "path-parse": "^1.0.5"
       }
     },
-    "node_modules/reselect": {
-      "version": "5.1.0",
-      "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.0.tgz",
-      "integrity": "sha512-aw7jcGLDpSgNDyWBQLv2cedml85qd95/iszJjN988zX1t7AVRJi19d9kto5+W7oCfQ94gyo40dVbT6g2k4/kXg=="
-    },
     "node_modules/resolve": {
       "version": "1.22.8",
       "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
@@ -14899,6 +14816,33 @@
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
       }
+    },
+    "node_modules/zustand": {
+      "version": "4.5.2",
+      "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.2.tgz",
+      "integrity": "sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==",
+      "dependencies": {
+        "use-sync-external-store": "1.2.0"
+      },
+      "engines": {
+        "node": ">=12.7.0"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.8",
+        "immer": ">=9.0.6",
+        "react": ">=16.8"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "immer": {
+          "optional": true
+        },
+        "react": {
+          "optional": true
+        }
+      }
     }
   }
 }

+ 1 - 3
package.json

@@ -9,7 +9,6 @@
     "web": "expo start --web"
   },
   "dependencies": {
-    "@reduxjs/toolkit": "^2.2.1",
     "@types/react-native-datepicker": "^1.7.6",
     "axios": "^1.6.7",
     "dotenv": "^16.4.5",
@@ -27,8 +26,7 @@
     "react-native-modern-datepicker": "^1.0.0-beta.91",
     "react-native-safe-area-context": "4.10.1",
     "react-native-screens": "3.31.1",
-    "react-redux": "^9.1.0",
-    "redux": "^5.0.1"
+    "zustand": "^4.5.2"
   },
   "devDependencies": {
     "@babel/core": "^7.20.0",

+ 8 - 0
providers/signup_form_store.tsx

@@ -0,0 +1,8 @@
+import { create } from "zustand";
+import { ISignUpStore } from "../types/signup_store";
+
+const useSignUpStore = create<ISignUpStore>((set) => ({
+    
+}));
+
+export default useSignUpStore;

+ 13 - 0
providers/test_store.tsx

@@ -0,0 +1,13 @@
+import { create } from "zustand";
+
+const useSignUpStore = create<{
+  value: number;
+  add: () => void;
+  minus: () => void;
+}>((set) => ({
+  value: 0,
+  add: () => set((prev) => ({ value: prev.value + 1 })),
+  minus: () => set((prev) => ({ value: prev.value - 1 })),
+}));
+
+export default useSignUpStore;

+ 0 - 23
reducers/counterReducer.tsx

@@ -1,23 +0,0 @@
-import { createSlice } from "@reduxjs/toolkit";
-
-export const counterSlice = createSlice({
-  name: "counter",
-  initialState: {
-    value: 0,
-  },
-  reducers: {
-    increment: (state) => {
-      state.value += 1;
-    },
-    decrement: (state) => {
-      state.value -= 1;
-    },
-    incrementByAmount: (state, action) => {
-      state.value += action.payload;
-    },
-  },
-});
-
-export const { increment, decrement, incrementByAmount } = counterSlice.actions;
-
-export default counterSlice.reducer;

+ 0 - 11
store.tsx

@@ -1,11 +0,0 @@
-import { configureStore } from "@reduxjs/toolkit";
-import counterReducer from "./reducers/counterReducer";
-
-const store = configureStore({
-  reducer: {
-    counter: counterReducer,
-    // Define a top-level state field named `todos`, handled by `todosReducer`
-  },
-});
-
-export default store;

+ 3 - 3
component/type.tsx → types/signup.d.ts

@@ -1,4 +1,4 @@
-export type FormData = {
+export type SignUpFormData = {
 	phone: string;
 	phoneVerificationStatus: boolean;
 	name: string;
@@ -13,6 +13,6 @@ export type FormData = {
 	paymentMethod: string;
 };
 
-export type FormDataKey = keyof FormData;
+export type SignUpFormDataKey = keyof SignUpFormData;
 
-export type HandleFormDataChange = <K extends FormDataKey>(field: K, value: FormData[K]) => void;
+export type HandleSignUpFormDataChange = <K extends SignUpFormDataKey>(field: K, value: SignUpFormData[K]) => void;

+ 3 - 0
types/signup_store.d.ts

@@ -0,0 +1,3 @@
+import { SignUpFormData } from "./signup";
+
+export interface ISignUpStore extends SignUpFormData {}