You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native中Axios POST请求重复执行问题求助

React Native注册功能POST请求重复提交问题

点击提交按钮后,Axios的POST请求会执行两次,数据库中新增两条记录,第一条为空数据,第二条为填写的有效数据。相关代码如下:

import React, { useState } from "react";
import { useNavigation } from "@react-navigation/native";
import { A } from "@expo/html-elements";
import { LogoImage } from "../assets/";
import MaterialIcons from "react-native-vector-icons/MaterialIcons";
import Checkbox from "expo-checkbox";
import axios from "axios";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { View, Text, Image, ScrollView, Pressable } from "react-native";
import {
  NativeBaseProvider,
  Button,
  FormControl,
  Input,
  Select,
} from "native-base";

const SignUp = (props) => {
  const navigation = useNavigation();
  const [show, setShow] = useState(false);
  const [isCondition, SetIsCondition] = useState(false);
  const [isLoading, setIsLoading] = useState(false);
  const [inputData, setInputData] = useState({
    userName: "",
    password: "",
    lastName: "",
    job: "",
    jobCategory: "",
  });
  
  const [isDataEmpty, setIsDataEmpty] = useState({
    userName: false,
    password: false,
    lastName: false,
    job: false,
    jobCategory: false,
  });

  const submitData = () => {
    if (
      inputData.userName != "" &&
      inputData.password.length >= 8 &&
      inputData.lastName != "" &&
      inputData.job != "" &&
      inputData.jobCategory != "" &&
      isCondition
    ) {
      // api
      setIsLoading(true);

      axios({
        method: "POST",
        url: "http://localhost/chantier237/API/AUTH/st_signup.php",
        responseType: "json",
        headers: { "Access-Control-Allow-Origin": "*" },
        data: {
          userName: inputData.userName,
          password: inputData.password,
          lastName: inputData.lastName,
          job: inputData.job,
          jobCategory: inputData.jobCategory,
        },
      })
        .then((response) => {
          console.log(response.data);
          if (response.data.status == "ERROR") {
            //TOAST THE ERROR
            console.log(response.data.message);
          } else {
            // save the datauser in state and in local

            AsyncStorage.setItem(
              "st_chantier237_user",
              JSON.stringify({
                userId: response.data.data.id,
                isAbonned: response.data.data.is_abon,
                dateAbonned: response.data.data.date_abon,
              })
            );

            props.setStateUser({
              userId: response.data.data.id,
              isAbonned: response.data.data.is_abon,
              dateAbonned: response.data.data.date_abon,
            });
          }
          // navigation.replace("Home");
        })
        .catch((error) => {
          // toat error
          console.log(error);
        })
        .finally(() => {
          setIsLoading(false);
        });
    } else {
      if (inputData.userName == "") {
        setIsDataEmpty((prev) => {
          return { ...prev, userName: true };
        });
      } else {
        setIsDataEmpty((prev) => {
          return { ...prev, userName: false };
        });
      }
      if (inputData.password.length < 8) {
        setIsDataEmpty((prev) => {
          return { ...prev, password: true };
        });
      } else {
        setIsDataEmpty((prev) => {
          return { ...prev, password: false };
        });
      }
      if (inputData.lastName == "") {
        setIsDataEmpty((prev) => {
          return { ...prev, lastName: true };
        });
      } else {
        setIsDataEmpty((prev) => {
          return { ...prev, lastName: false };
        });
      }
      if (inputData.job == "") {
        setIsDataEmpty((prev) => {
          return { ...prev, job: true };
        });
      } else {
        setIsDataEmpty((prev) => {
          return { ...prev, job: false };
        });
      }
      if (inputData.jobCategory == "") {
        setIsDataEmpty((prev) => {
          return { ...prev, jobCategory: true };
        });
      } else {
        setIsDataEmpty((prev) => {
          return { ...prev, jobCategory: false };
        });
      }
      if (!isCondition) {
        console.log("condition not");
      }
    }
  };

  return (
    <NativeBaseProvider>
      <ScrollView className="bg-white flex-1">
        <View className="items-center justify-center pt-7 w-full pb-10">
          <View className="w-32 h-32 mb-2">
            <Image source={LogoImage} className="w-full h-full object-cover" />
          </View>
          <View className="flex-col items-center justify-center w-full">
            <Text className="text-[30px] text-[black] mb-1 text-bold">
              Inscription
            </Text>
            <Text>creer votre compte</Text>
          </View>

          <View className="w-full px-8 items-center justify-center flex-col pt-5 gap-5">
            <FormControl isInvalid={isDataEmpty.userName}>
              <Input
                placeholder="Nom d'utilisateur"
                type="text"
                className="text-sm"
                name="userName"
                onChangeText={(value) =>
                  setInputData({ ...inputData, userName: value })
                }
              />
              <FormControl.HelperText>
                Veuillez renseigner un seul nom
              </FormControl.HelperText>
              <FormControl.ErrorMessage>
                Ce champ ne doit pas etre vide.
              </FormControl.ErrorMessage>
            </FormControl>

            <FormControl isInvalid={isDataEmpty.lastName}>
              <Input
                placeholder="Votre nom"
                type="text"
                className="text-sm"
                onChangeText={(value) =>
                  setInputData({ ...inputData, lastName: value })
                }
              />
              <FormControl.ErrorMessage>
                Ce champ ne doit pas etre vide.
              </FormControl.ErrorMessage>
            </FormControl>

            <FormControl isInvalid={isDataEmpty.password}>
              <Input
                placeholder="Mot de passe"
                type={show ? "text" : "password"}
                className="text-sm"
                onChangeText={(value) =>
                  setInputData({ ...inputData, password: value })
                }
                InputRightElement={
                  <Pressable onPress={() => setShow(!show)}>
                    <MaterialIcons
                      name={show ? "visibility" : "visibility-off"}
                      size={25}
                      mr="2"
                      color="black"
                      style={{ marginRight: 13 }}
                    />
                  </Pressable>
                }
              />
              <FormControl.ErrorMessage>
                Le mot de passe doit contenir au moins 8 caracteres
              </FormControl.ErrorMessage>
            </FormControl>

            <FormControl isInvalid={isDataEmpty.job}>
              <Input
                placeholder="Nom de votre metier"
                type="text"
                className="text-sm"
                onChangeText={(value) =>
                  setInputData({ ...inputData, job: value })
                }
              />
              <FormControl.ErrorMessage>
                Ce champ ne doit pas etre vide.
              </FormControl.ErrorMessage>
            </FormControl>

            <FormControl isInvalid={isDataEmpty.jobCategory}>
              <Select
                accessibilityLabel="Selectionner votre categorie"
                placeholder="Selectionner votre categorie"
                className="text-sm"
                _selectedItem={{
                  bg: "teal.600",
                }}
                mt="1"
                onValueChange={(value) =>
                  setInputData({ ...inputData, jobCategory: value })
                }
              >
                <Select.Item label="UX Research" value="ux" />
                <Select.Item label="Web Development" value="web" />
                <Select.Item label="Cross Platform Development" value="cross" />
                <Select.Item label="UI Designing" value="ui" />
                <Select.Item label="Backend Development" value="backend" />
              </Select>
              <FormControl.ErrorMessage>
                Ce champ ne doit pas etre vide.
              </FormControl.ErrorMessage>
            </FormControl>

            <FormControl className="w-full px-7">
              <View className="flex-row text-center items-center justify-start">
                <Checkbox
                  value={isCondition}
                  onValueChange={SetIsCondition}
                  color="blue"
                />
                <Text className="text-center text-sm">
                  J'accepte les{" "}
                  <A
                    href="https://stcode-portfolio.netlify.app"
                    style={{
                      color: "blue",
                      textDecorationLine: "underline",
                    }}
                  >
                    termes et conditions d'utilisation{" "}
                  </A>
                  et la{" "}
                  <A
                    href="https://stcode-portfolio.netlify.app"
                    style={{
                      color: "blue",
                      textDecorationLine: "underline",
                    }}
                  >
                    politique de confidentialite
                  </A>
                </Text>
              </View>
            </FormControl>

            <Button
              style={{
                backgroundColor: "black",
                width: "100%",
                height: 60,
                borderRadius: 7,
                fontSize: 25,
              }}
              onPress={submitData}
              size="lg"
              colorScheme="black"
              isLoading={isLoading}
              isLoadingText="Inscription"
            >
              S'inscrire
            </Button>

            <Text className="items-center justify-center w-full text-center">
              Vous avez deja un compte ?{"  "}
              <Text
                className="text-[15px] text-blue-700"
                onPress={() => {
                  navigation.navigate("Signin");
                }}
              >
                Connectez-vous
              </Text>
            </Text>
          </View>
        </View>
      </ScrollView>
    </NativeBaseProvider>
  );
};

export default SignUp;

问题原因及解决方法

常见触发原因

  1. React Strict Mode 重复执行副作用:开发环境下,React Strict Mode会刻意重复执行副作用函数(如Axios请求),用于检测潜在代码问题,这是此类重复提交的高频诱因。
  2. 按钮事件重复绑定:组件重渲染可能导致onPress事件被多次注册,或者用户误触按钮两次。
  3. 状态更新引发重渲染:submitData中的状态更新(如setIsLoading、setIsDataEmpty)可能触发组件重渲染,进而导致请求逻辑再次执行。

具体修复方案

  1. 禁用React Strict Mode
    找到项目入口文件(通常是App.js或index.js),移除包裹组件的<StrictMode>标签:

    // 原代码
    <StrictMode>
      <NavigationContainer>...</NavigationContainer>
    </StrictMode>
    
    // 修改后
    <NavigationContainer>...</NavigationContainer>
    
  2. 添加请求锁阻止重复触发
    在submitData函数开头增加判断,避免请求在未完成时再次执行:

    const submitData = () => {
      if (isLoading) return; // 新增此行,阻止重复触发
      // 原有逻辑...
    }
    
  3. 合并状态更新减少重渲染
    将else块中多次调用的setIsDataEmpty合并为一次,减少不必要的组件重渲染:

    // 替换原else块中的多个setIsDataEmpty
    setIsDataEmpty({
      userName: inputData.userName === "",
      password: inputData.password.length < 8,
      lastName: inputData.lastName === "",
      job: inputData.job === "",
      jobCategory: inputData.jobCategory === ""
    });
    
  4. 检查组件是否重复挂载
    确认SignUp组件是否在父组件中被多次渲染,比如是否嵌套在多个NativeBaseProvider或导航容器中,确保组件只被挂载一次。

内容的提问来源于stack exchange,提问作者Thierry SITIO

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 11:42:38