javascript - Postman 中的 API 工作正常但在 React Native 中出现 422 错误

标签 javascript reactjs react-native axios react-hooks

我有一个名为 NTCPDiamondScreen.js 的组件/屏幕,我在其中发起了一个发布请求,我创建了一个名为 ProjectContext.js 的上下文(并在其中使用了 useReducer),以便管理操作/状态。我不知道为什么我会收到 Unprocessable entity 422 错误,即使我在 Postman 上测试它时,它工作正常,没有任何错误:

Request failed with status code 422
- node_modules\axios\lib\core\createError.js:15:17 in createError
- node_modules\axios\lib\core\settle.js:16:9 in settle
- node_modules\axios\lib\adapters\xhr.js:52:6 in handleLoad
- node_modules\event-target-shim\dist\event-target-shim.js:818:39 in 
EventTarget.prototype.dispatchEvent
- node_modules\react-native\Libraries\Network\XMLHttpRequest.js:566:23 in setReadyState
- node_modules\react-native\Libraries\Network\XMLHttpRequest.js:388:25 in __didCompleteResponse
- node_modules\react-native\Libraries\vendor\emitter\EventEmitter.js:190:12 in emit
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:436:47 in __callFunction
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:111:26 in __guard$argument_0
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:384:10 in __guard
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:110:17 in __guard$argument_0
* [native code]:null in callFunctionReturnFlushedQueue

NTCPDiamondScreen.js

import React, { useRef, useState, useContext, useEffect } from "react";
import {
  Dimensions,
  PanResponder,
  View,
  StyleSheet,
  Text,
  Alert,
  AsyncStorage,
} from "react-native";
import { Button } from "react-native-elements";
import Svg, { Polyline } from "react-native-svg";
import RadioForm from "react-native-simple-radio-button";
import Loader from "../components/Loader";
import { Context as ProjectContext } from "../context/ProjectContext";
import { navigate } from "../navigationRef";

const examplePath = [];
var diamond = [
  { criteria: { novelty: "", technology: "", complexity: "", pace: "" } },
];

var retrievingObjForStorage = {};

const retrievingObjForStorageFunc = async () => {
  try {
    const retrievingObjForStorageString = await AsyncStorage.getItem(
      "Project&CompanyDetails"
    );
    retrievingObjForStorage = JSON.parse(retrievingObjForStorageString);
  } catch (err1) {
    console.log(err1);
  }
};

var technology = [
  { label: "Super-high", value: "Super-high" },
  { label: "High", value: "High" },
  { label: "Medium", value: "Medium" },
  { label: "Low", value: "Low" },
];

var pace = [
  { label: "Regular", value: "Regular" },
  { label: "Fast", value: "Fast" },
  { label: "Time-critical", value: "Time-critical" },
  { label: "Blitz", value: "Blitz" },
];

var complexity = [
  { label: "Assembly", value: "Assembly" },
  { label: "System", value: "System" },
  { label: "Array", value: "Array" },
];

var novelty = [
  { label: "Derivative", value: "Derivative" },
  { label: "Platform", value: "Platform" },
  { label: "Breakthrough", value: "Breakthrough" },
];

const GesturePath = ({ path, color, children }) => {
  const { width, height } = Dimensions.get("window");
  const points = path.map((p) => `${p.x},${p.y}`).join(" ");
  return (
    <>
      <Svg
        height="400"
        width="400"
        viewBox={`0 0 ${width} ${height}`}
        //style={{ borderWidth: 5, borderColor: "black" }}
      >
        <Polyline points={points} fill="none" stroke={color} strokeWidth="5" />
      </Svg>
      {children}
    </>
  );
};

const GestureRecorder = ({ onPathChanged, children }) => {
  const pathRef = useRef([]);

  const panResponder = useRef(
    PanResponder.create({
      //onStartShouldSetPanResponder: () => true,
      // onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
      // onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
      onMoveShouldSetPanResponder: () => true,

      onPanResponderGrant: () => {
        pathRef.current = [];
      },
      onPanResponderMove: (event) => {
        pathRef.current.push({
          x: event.nativeEvent.locationX,
          y: event.nativeEvent.locationY,
        });

        onPathChanged([...pathRef.current]);
      },
      onPanResponderRelease: () => {
        onPathChanged([...pathRef.current]);
      },
    })
  ).current;

  return (
    <View
      style={[StyleSheet.absoluteFill, styles.container]}
      {...panResponder.panHandlers}
    >
      {children}
    </View>
  );
};

const NTCPDiamondScreen = () => {
  useEffect(() => {
    retrievingObjForStorageFunc();
  }, []);

  const [path, setPath] = useState(examplePath);
  const [techVal, setTechVal] = useState("");
  const [noveltyVal, setNoveltyVal] = useState("");
  const [complexityVal, setComplexityVal] = useState("");
  const [paceVal, setPaceVal] = useState("");
  const [loading, setLoading] = useState(false);
  const { addNewProject } = useContext(ProjectContext);

  const resetState = () => {
    setPath([]);
    setTechVal("");
    setNoveltyVal("");
    setComplexityVal("");
    setPaceVal("");
  };

  const createTwoButtonAlert = () =>
    Alert.alert(
      "Success",
      "Your new project is successfully added!",
      [{ text: "OK", onPress: () => console.log("OK Pressed") }],
      { cancelable: false }
    );

  const {
    projectName,
    projectDescription,
    projectBudget,
    projectDuration,
    industry,
    companyName,
    numberOfEmployees,
  } = retrievingObjForStorage;

  return (
    <View
      style={{
        flex: 1,

        backgroundColor: "#fff",
        // /position: "absolute",
      }}
    >
      <Loader loading={loading} />

      <Button
        title="Press the buttons (and join them by lines, optional) to make your diamond"
        onPress={() => {}}
        type="solid"
        buttonStyle={{
          backgroundColor: "#33CCFF",
        }}
        titleStyle={{ fontFamily: "sans-serif-light" }}
      />
      <View
        style={{
          flex: 1,
          borderWidth: 1,
          borderColor: "#E7F0F0",
          marginTop: 16,
          marginBottom: 30,
        }}
      >
        <GesturePath path={path} color="#33CCFF"></GesturePath>

        <GestureRecorder onPathChanged={setPath}></GestureRecorder>
      </View>

      <View
        style={{
          //borderColor: "blue",
          //borderWidth: 5,
          position: "absolute",
          marginTop: 80,
          marginLeft: 30,
          //flex: 1,
          backgroundColor: "rgba(255, 255, 255, 0.001)",
        }}
      >
        <View
          style={{
            paddingLeft: 145,
            postion: "absolute",
          }}
        >
          <Text
            style={{
              fontSize: 10,
              fontFamily: "sans-serif-light",

              fontStyle: "italic",
              paddingLeft: 30,
              color: "#B4BFC3",
            }}
          >
            Technology
          </Text>
          <RadioForm
            radio_props={technology}
            initial={-1}
            onPress={(value) => {
              setTechVal(value);
              diamond[0].criteria.technology = techVal;
              //console.log(`Tech = ${newDiamond[0].newCriteria.technology}`);
            }}
            buttonColor={"#33CCFF"}
            buttonSize={10}
            selectedButtonColor={"#33CCFF"}
            labelStyle={{
              fontFamily: "sans-serif-light",

              fontSize: 7,
            }}
            style={{}}
          />
        </View>
        <View style={{ flexDirection: "row" }}>
          <View>
            <View
              style={{
                marginRight: 10,
              }}
            >
              <Text
                style={{
                  fontSize: 10,
                  fontFamily: "sans-serif-light",

                  fontStyle: "italic",
                  paddingLeft: 30,
                  paddingBottom: 5,
                  color: "#B4BFC3",
                }}
              >
                Novelty
              </Text>
              <RadioForm
                radio_props={novelty}
                initial={-1}
                formHorizontal={true}
                labelHorizontal={false}
                onPress={(value) => {
                  setNoveltyVal(value);
                  diamond[0].criteria.novelty = noveltyVal;
                }}
                buttonColor={"#33CCFF"}
                buttonSize={10}
                selectedButtonColor={"#33CCFF"}
                labelStyle={{
                  fontFamily: "sans-serif-light",

                  fontSize: 7,
                }}
              />
            </View>
          </View>

          <View
            style={{
              marginLeft: 40,
            }}
          >
            <Text
              style={{
                fontSize: 10,
                fontFamily: "sans-serif-light",

                fontStyle: "italic",
                paddingLeft: 30,
                paddingBottom: 5,
                color: "#B4BFC3",
              }}
            >
              Complexity
            </Text>
            <RadioForm
              radio_props={complexity}
              initial={-1}
              formHorizontal={true}
              labelHorizontal={false}
              onPress={(value) => {
                setComplexityVal(value);
                diamond[0].criteria.complexity = complexityVal;
              }}
              buttonColor={"#33CCFF"}
              buttonSize={10}
              selectedButtonColor={"#33CCFF"}
              labelStyle={{
                fontFamily: "sans-serif-light",

                fontSize: 7,
              }}
            />
          </View>
        </View>
        <View
          style={{
            paddingLeft: 145,
          }}
        >
          <Text
            style={{
              fontSize: 10,
              fontFamily: "sans-serif-light",

              fontStyle: "italic",
              paddingLeft: 30,
              color: "#B4BFC3",
            }}
          >
            Pace
          </Text>
          <RadioForm
            radio_props={pace}
            initial={-1}
            onPress={(value) => {
              setPaceVal(value);
              diamond[0].criteria.pace = paceVal;
            }}
            buttonColor={"#33CCFF"}
            buttonSize={10}
            selectedButtonColor={"#33CCFF"}
            labelStyle={{
              fontFamily: "sans-serif-light",

              fontSize: 7,
            }}
            style={{}}
          />
        </View>
      </View>

      <Button
        title="Save and Continue"
        onPress={() => {
          setLoading(true);

          setTimeout(() => {
            setLoading(false);
            console.log(diamond);

            addNewProject({
              projectName,
              projectDescription,
              projectBudget,
              projectDuration,
              industry,
              companyName,
              numberOfEmployees,
              diamond,
            });

            createTwoButtonAlert();
            resetState();
            navigate("ViewProjects");
          }, 2500);
        }}
        type="solid"
        buttonStyle={{
          backgroundColor: "#33CCFF",
          marginBottom: 10,
        }}
        titleStyle={{ fontFamily: "sans-serif-light" }}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    backgroundColor: "rgba(255,255,255,0.01)",
  },
});

NTCPDiamondScreen.navigationOptions = {
  title: "Create New Diamond",
};

export default NTCPDiamondScreen;

ProjectContext.js

import createDataContext from "./createDataContext";
import diamondApi from "../api/diamondApi";

const projectReducer = (state, action) => {
  switch (action.type) {
    case "add_user_error":
      return { ...state, userErrorMessage: action.payload };
    case "clear_user_error_message":
      return { ...state, userErrorMessage: "" };
    default:
      return state;
  }
};

const addNewProject = (dispatch) => async ({
  projectName,
  projectDescription,
  projectBudget,
  projectDuration,
  industry,
  companyName,
  numberOfEmployees,
  diamond,
}) => {
  try {
    await diamondApi.post("/projects", {
      projectName,
      projectDescription,
      projectBudget,
      projectDuration,
      industry,
      companyName,
      numberOfEmployees,
      diamond,
    });
  } catch (err) {
    console.log(err);

    dispatch({
      type: "add_user_error",
      payload: "Could not post project. Go back and try again.",
    });
  }
};

const clearUserErrorMessage = (dispatch) => () => {
  dispatch({
    type: "clear_user_error_message",
  });
};

export const { Provider, Context } = createDataContext(
  projectReducer,
  { addNewProject, clearUserErrorMessage },
  { userErrorMessage: "" }
);

包含 axios 实例的文件(diamondApi.js):

import axios from "axios";
import { AsyncStorage } from "react-native";
const instance = axios.create({
  baseURL: "http://5b4bc1a6edd6.ngrok.io",
});

instance.interceptors.request.use(
  async (config) => {
    const token = await AsyncStorage.getItem("token");

    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (err) => {
    return Promise.reject(err);
  }
);

export default instance;

最佳答案

您是否在模拟器上运行您的 React Native 项目。你也可以添加你的后台端点吗。

关于javascript - Postman 中的 API 工作正常但在 React Native 中出现 422 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62726634/

相关文章:

javascript - 使用 ShouldJS 比较来自 Mongoose 的数组

javascript - 如何将选择元素的值放入文本区域?

javascript - 如何将时间格式化为 dayjs 对象?

css - React 在鼠标悬停时添加图像,平滑过渡

javascript - 注册 Amazon Web Service Cognito 错误 InvalidParameterException

javascript - 有没有办法根据 firebase 角色保护 url?

javascript - 使用 JSON 从 JavaScript/jQuery 中的 PHP 获取数组,然后对其进行操作?

css - 有没有办法让 react 选择具有可折叠的组?

ios - 我在为 ios 构建 expo 应用程序时遇到错误

android - error "Process ' command './node_modules/expokit/detach-scripts/run-exp.sh' ' finished with non-zero exit value 1"whie getting android apk file