skip to Main Content

We are developing an application using React Native and everything was going smoothly. We decided to upgrade ReactNative (and other packages) from 0.70.4 to 0.71.3 and since then, two screens don’t work anymore.

On Android, we are getting a Render Error: Attempting to change configurable attribute of unconfigurable property:

RenderError on Android

On iOS, it’s Render Error: the property is not configurable:

RenderError on iOS

For example, we are fetching a recipe from the remote back-end using Axios:

  const fetchOneRecipe = () => {
    axiosInstance
      .get(getUrl())
      .then((res) => {
        setMyRecipe(res.data);
        setLoading(false);
      })
      .catch((err) => {
        setLoading(false);
        console.log("error one recipe: ", err);
      });
  };

When displaying an attribute of the recipe with an unknown number of children (like the ingredients or related categories), we are using the Array.map function:

{Object.values(myRecipe?.relatedTraits).map((trait) => {
   return trait.traitSetCode === "COURSES" ||
      trait.traitSetCode === "PREPARATION_METHODS" ||
      trait.traitSetCode === "MAIN_INGREDIENTS" ? (
      <View>
         <Text style={Styles.h4Black60}>
            {trait.name}
            {"      "}
         </Text>
      </View>
   ) : null;
})}

Using these two piece of code together create the above mentioned error.

If we remove all the Array.map functions of the screen, then there’s no error (but missing data). All the other data of the recipe not using Array.map are displayed correctly.

Other screens using Axios but no Array.map are working fine. Other screens using Array.map but not Axios are working fine. The other screen using Axios and Array.map get the same error.

We tried using Array.foreach, but the same error appears. When rolling back the React-Native upgrade, it is working fine.

UPDATE:

We simplified the screen with the minimal render but still have the error:

import React, { useState, useEffect } from "react";
import {
  View,
  Text,
  SafeAreaView,
  ScrollView,
} from "react-native";
import Styles from "../../Styles/Styles";
import SousHeader from "../../Components/SousHeader";
import { oneRecipe } from "../../interface/interface";
import { axiosInstance } from "../../API/API";
import { useRoute } from "@react-navigation/native";
import urls from "../../Services/Services";
import { useSelector } from "react-redux";
import Spinner from "../../Components/Spinner";

const RecipeViewScreen = () => {
  const route: any = useRoute();
  const recipeId: number = route.params?.recipeID;
  const [loading, setLoading] = useState<boolean>(true);
  const [myRecipe, setMyRecipe] = useState<oneRecipe>();
  const [versionId] = useState<number>(recipeId);

  const language = useSelector((state: any) => state.language.language);

  useEffect(() => {
    fetchOneRecipe();
  }, []);

  const fetchOneRecipe = () => {
    axiosInstance
      .get(getUrl())
      .then((res) => {
        setMyRecipe(res.data);
        setLoading(false);
      })
      .catch((err) => {
        setLoading(false);
        console.log("error one recipe: ", err);
      });
  };

  let getUrl = (): string => {
    //Original URL
    //let text = `${urls.oneRecipe(versionId, language)}`;
    let text = "https://jsonplaceholder.typicode.com/todos";
    return text;
  };

  //Return false
  const isHermes = () => !!global.HermesInternal;
  console.log(isHermes());

  return (
    <SafeAreaView>
      <View style={Styles.container}>
        <SousHeader title={myRecipe?.name} />
        <ScrollView>
          {loading ? (
            <Spinner />
          ) : (
            <>
              {myRecipe !== undefined && (
                <>
                        <>
                          {/* Original text */}
                          {/*{Object.values(myRecipe?.relatedTraits).map((trait) => {*/}
                          {/*  return trait.traitSetCode === "COURSES" ||*/}
                          {/*  trait.traitSetCode === "PREPARATION_METHODS" ||*/}
                          {/*  trait.traitSetCode === "MAIN_INGREDIENTS" ? (*/}
                          {/*      <View>*/}
                          {/*        <Text style={Styles.h4Black60}>*/}
                          {/*          {trait.name}*/}
                          {/*          {"      "}*/}
                          {/*        </Text>*/}
                          {/*      </View>*/}
                          {/*  ) : null;*/}
                          {/*})}*/}
                          {Object.values(myRecipe).map((trait) => {
                            return trait.id === 2 ||
                            trait.id === 4 ||
                            trait.id === 6 ? (
                                <View>
                                  <Text>
                                    {trait.title}
                                    {"      "}
                                  </Text>
                                </View>
                            ) : null;
                          })}
                        </>
                </>
              )}
            </>
          )}
        </ScrollView>
      </View>
    </SafeAreaView>
  );
};

export default RecipeViewScreen;

Here’s our composer.json:

{
  "name": "sfw",
  "version": "0.1.40",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "lint": "eslint .",
    "start": "react-native start",
    "test": "jest"
  },
  "dependencies": {
    "@fortawesome/fontawesome-svg-core": "6.3.0",
    "@fortawesome/free-solid-svg-icons": "6.3.0",
    "@fortawesome/react-native-fontawesome": "0.3.0",
    "@react-native-async-storage/async-storage": "1.17.11",
    "@react-native-community/checkbox": "0.5.14",
    "@react-native-community/cli-platform-ios": "10.2.0",
    "@react-native-community/datetimepicker": "6.7.5",
    "@react-native-google-signin/google-signin": "9.0.2",
    "@react-native-picker/picker": "2.4.8",
    "@react-navigation/drawer": "6.6.2",
    "@react-navigation/native": "6.1.6",
    "@react-navigation/stack": "6.3.16",
    "@reduxjs/toolkit": "1.9.3",
    "@rneui/themed": "4.0.0-rc.7",
    "@types/react-native-version-check": "3.4.5",
    "axios": "1.3.4",
    "formik": "2.2.9",
    "moment": "2.29.4",
    "react": "18.2.0",
    "react-native": "0.71.3",
    "react-native-collapsible-tab-view": "6.0.1",
    "react-native-element-dropdown": "2.8.0",
    "react-native-fbsdk-next": "11.1.0",
    "react-native-gesture-handler": "^2.9.0",
    "react-native-gradle-plugin": "0.71.16",
    "react-native-image-viewing": "0.2.2",
    "react-native-localize": "2.2.5",
    "react-native-modal": "13.0.1",
    "react-native-modal-datetime-picker": "14.0.1",
    "react-native-pager-view": "^6.1.4",
    "react-native-paper": "5.3.1",
    "react-native-reanimated": "^3.0.2",
    "react-native-render-html": "6.3.4",
    "react-native-safe-area-context": "^4.5.0",
    "react-native-screens": "^3.20.0",
    "react-native-splash-screen": "3.3.0",
    "react-native-svg": "^13.8.0",
    "react-native-vector-icons": "9.2.0",
    "react-native-version-check": "3.4.7",
    "react-native-webview": "11.26.1",
    "react-redux": "8.0.5",
    "redux": "4.2.1",
    "redux-persist": "6.0.0",
    "yup": "0.32.11"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0",
    "@babel/preset-env": "^7.20.0",
    "@babel/runtime": "^7.20.5",
    "@react-native-community/eslint-config": "^3.2.0",
    "@tsconfig/react-native": "^2.0.2",
    "@types/jest": "^29.2.1",
    "@types/react": "^18.0.24",
    "@types/react-native-fbsdk": "^3.0.2",
    "@types/react-native-vector-icons": "^6.4.10",
    "@types/react-test-renderer": "^18.0.0",
    "babel-jest": "^29.2.1",
    "eslint": "^8.19.0",
    "jest": "^29.2.1",
    "metro-react-native-babel-preset": "^0.73.7",
    "mocha": "^10.1.0",
    "prettier": "^2.4.1",
    "react-test-renderer": "18.2.0",
    "typescript": "^4.8.4"
  },
  "resolutions": {
    "@types/react": "^17",
    "react-devtools-core": "4.14.0"
  },
  "jest": {
    "preset": "react-native",
    "moduleFileExtensions": [
      "ts",
      "tsx",
      "js",
      "jsx",
      "json",
      "node"
    ]
  },
  "main": "index.js",
  "license": "MIT"
}

But we also found that after getting the error in the emulator, if we change something in the screen and saving, the page reload and the error disappears.

NEW UPDATE:

By trying to solve this we found out that it seems to be a problem when navigating to the screen through navigation.navigate or navigation.dispatch. When we put a malfunctioning screen as the root of the Stack.navigator, it works:

return (
  <Stack.Navigator>
    <Stack.Screen name="recipeview" component={RecipeViewScreen} />
  </Stack.Navigator>
);

But trying to access it by navigation functions doesnt work:

<Text
  onPress={() =>
    navigation.navigate('recipeview' as never)
  }
>
  Test
</Text>

2

Answers


  1. Chosen as BEST ANSWER

    Finally found out the error. It was caused by the fact that the elements inside map functions didn't have a key attributes.

    The same error also appears when misnaming an icon in "react-native-vector-icons/FontAwesome"

    Our guess is that we have a configuration error somewhere. When the emulator encounter an error (missing key attributes, icon not found), it tries to log it somewhere but can't and crash, showing the "Render Error: Attempting to change configurable attribute of unconfigurable property" instead of the real relevant error.


  2. I just have the same error and it was fixed by adding key to every child component that you map.

    {Object.values(myRecipe?.relatedTraits).map((trait, index) => {
        return trait.traitSetCode === "COURSES" ||
        trait.traitSetCode === "PREPARATION_METHODS" ||
        trait.traitSetCode === "MAIN_INGREDIENTS" ? (
        <View key={index}>
           <Text style={Styles.h4Black60}>
              {trait.name}
              {"      "}
           </Text>
        </View>
       ) : null;
    })}
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search