0

I have created a React Context API, I have stored information such as first_name, hobbies, DOB etc in it. I have crated a state in the context file and a function that changes the state when called. I am using the context in SignUpForm1.js and SignUpForm2.js, I am trying to update the state of context variables when ever there is a change in the text field, but the data in the context is not updating.

UserData.js (Context)

import React from "react";
import { useState } from "react";
import {Text} from 'react-native';
import { createContext } from "react";


const SignUpContext = React.createContext({});

const UserData = (props)=>{

  var state = {
    pref_pronoun: "",
    DOB: "",
    course: "",
    first_name: "",
    hobby_1: "",
    hobby_2: "",
    hobby_3: "",
    hobby_4: "",
    hobby_5: "",
    home_city: "",
    last_name: "",
    nationality: "",
    student_email: "",
    university: "",
  }

  const [userDetails , setDetails] = useState(state);

  const updateFormData = (field, value) => {
    setDetails({ [field]: value });
    console.log(state);
  };

  return (
    <SignUpContext.Provider value = {{state, updateFormData}}>
      {props.children}
    </SignUpContext.Provider>
  )

}

export {SignUpContext, UserData} ;

SignUpForm1.js


import {
  Image,
  Text,
  StyleSheet,
  View,
  StatusBar,
  ScrollView,
  RefreshControl,
} from "react-native";
import DropDown from "./DropDown";
import Input from "./Input";
import {
  KeyboardAvoidingView,
  TouchableWithoutFeedback,
  Keyboard,
} from "react-native";
import { useCallback, useContext, useState } from "react";
import CustomButton from "./CustomButton";
import { useNavigation } from "@react-navigation/native";
import DateTimePickerModal from "react-native-modal-datetime-picker";
import { Button } from "react-native";
import { SignUpContext, UserData } from "./GlobalUtil/UserData";

const HideKeyboard = ({ children }) => (
  <TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
    {children}
  </TouchableWithoutFeedback>
);

function SignUpForm1() {
  

  const [isDatePickerVisible, setDatePickerVisibility] = useState(false);
  const s_context = useContext(SignUpContext);

  const showDatePicker = () => {
    setDatePickerVisibility(true);
  };

  const hideDatePicker = () => {
    setDatePickerVisibility(false);
  };


  const navigation = useNavigation();
  const NationalityData = ["Football", "Cricket", "Programmming", "Coding"];
  const [refreshing, setRefreshing] = useState(false);

  const onRefresh = useCallback(() => {
    setRefreshing(true);
    setTimeout(() => {
      setRefreshing(false);
    }, 2000);
  }, []);
  const statusBarHeight = Platform.OS === "ios" ? 50 : StatusBar.currentHeight;

  return (

        <KeyboardAvoidingView behavior="padding">
          <HideKeyboard>
            <View
              style={{
                height: "100%",
                width: "100%",
                backgroundColor: "#f1be63",
              }}
            >
              <View
                style={{ backgroundColor: "#f1be63", height: statusBarHeight }}
              >
                <StatusBar barStyle="dark-content" />
              </View>
              <ScrollView
                contentContainerStyle={styles.rootContainer}
                refreshControl={
                  <RefreshControl
                    refreshing={refreshing}
                    onRefresh={onRefresh}
                  />
                }
              >
                <Image
                  source={require("../assets/aeroplane.png")}
                  style={styles.image}
                  resizeMode="contain"
                />
                <Text style={styles.header}>Let's get you set up</Text>
                <Text style={styles.lowerHeader}>
                  (we promise that it won't take long)
                </Text>

                <View style={[styles.textFieldsContainer]}>
                  <View style={{ alignItems: "center" }}>
                    <Input
                      isLabel={true}
                      label="Preferred Pronoun"
                      placeholder="He/Him"
                      onChangeText={(text) => {
                        s_context.updateFormData("pref_pronoun", text);
                      }}
                    />
                    <Input
                      isLabel={true}
                      label="First Name"
                      placeholder="Cameron"
                      onChangeText={(text) => {
                        s_context.updateFormData("first_name", text);
                      }}
                    />
                    <Input
                      isLabel={true}
                      label="Last Name"
                      placeholder="Cox"
                      onChangeText={(text) => {
                        s_context.updateFormData("last_name", text);
                      }}
                    />
                    <View
                      style={{
                        backgroundColor: "white",
                        width: "80%",
                        borderRadius: 5,
                        marginTop: 10,
                      }}
                    >
                      <Button
                        title="Date of Birth"
                        onPress={showDatePicker}
                        color="gray"
                      />
                    </View>
                    <DateTimePickerModal
                      isVisible={isDatePickerVisible}
                      mode="date"
                      onConfirm={(date) => {
                        s_context.updateFormData('dob', date);
                        hideDatePicker();
                      }}
                      onCancel={hideDatePicker}
                      buttonTextColorIOS="white"
                      pickerContainerStyleIOS={{ backgroundColor: "#D89D35" }}
                      isDarkModeEnabled
                    />
                  </View>

                  <View style={{ alignItems: "center" }}>
                    <DropDown
                      data={NationalityData}
                      placeholder="Nationality"
                      onSelect={(selectedItem, index) => {
                        s_context.updateFormData("nationality", selectedItem);
                        }}
                    />
                    <DropDown
                      data={NationalityData}
                      placeholder="University"
                      onSelect={(selectedItem, index) => {
                        s_context.updateFormData("university", selectedItem);
                        }}
                    />
                    <DropDown
                      data={NationalityData}
                      placeholder="Course"
                      onSelect={(selectedItem, index) => {
                        s_context.updateFormData("course", selectedItem);
                        }}
                    />
                    <DropDown
                      data={NationalityData}
                      placeholder="HomeTown City"
                      onSelect={(selectedItem, index) => {
                        s_context.updateFormData("homeCity", selectedItem);
                        }}
                    />
                    <CustomButton
                      isBorder={true}
                      title="Next"
                      onPress={() => {
                        navigation.navigate("SignUp2");
                      }}
                    />
                  </View>
                </View>
              </ScrollView>
            </View>
          </HideKeyboard>
        </KeyboardAvoidingView>
  );
}

const styles = StyleSheet.create({
  rootContainer: {
    height: "125%",
    justifyContent: "flex-start",
    alignItems: "center",
    marginTop: 24,
  },
  textFieldsContainer: {
    width: "100%",
    flex: 1,
  },
  image: {
    width: "25%",
    height: "10%",
    marginTop: 24,
  },
  header: {
    color: "white",
    fontSize: 26,
    fontWeight: "bold",
    marginVertical: 6,
  },
  lowerHeader: {
    color: "white",
    fontSize: 12,
    marginBottom: 24,
  },
});
export default SignUpForm1;

SignUpForm2.js


import {
  View,
  Text,
  TouchableWithoutFeedback,
  StyleSheet,
  StatusBar,
  ScrollView,
} from "react-native";

import { KeyboardAvoidingView } from "react-native";
import { Avatar } from "react-native-elements";
import Input from "./Input";
import DropDown from "./DropDown";
import { Keyboard } from "react-native";
import { Platform } from "react-native";
import { useNavigation } from "@react-navigation/native";
import CustomButton from "./CustomButton";
import { useState, useContext } from "react";
import { createNewUser } from "./util/auth";
import { SignUpContext, UserData } from "./GlobalUtil/UserData";

const HideKeyboard = ({ children }) => (
  <TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
    {children}
  </TouchableWithoutFeedback>
);

function SignUpForm2() {

  const s_context = useContext(SignUpContext);


  async function FinishBtnHandler()
   {
    console.log("Creating New User");
    console.log("Email: " + emailText.trim());
    console.log("Password: " + passwordText.trim());
    await createNewUser(emailText.trim(), passwordText.trim());

  }

  const navigation = useNavigation();
  const hobbiesData = ["Football", "Cricket", "Programmming", "Coding"];

  const [emailText, setEmailText] = useState("");
  function handleEmailText(newText) {
    console.log("Email: " + newText);
    setEmailText(newText);
  }
  const [passwordText, setPasswordText] = useState("");
  function handlePasswordText(newText) {
    console.log("Password: " + newText);
    setPasswordText(newText);
  }

  function avatarPressHandler() {
    console.log("Pressed!");
  }
  const statusBarHeight = Platform.OS === "ios" ? 50 : StatusBar.currentHeight;
  return (
        <KeyboardAvoidingView behavior="padding" style={{ flex: 1 }}>
          <HideKeyboard>
            <ScrollView>
              <View
                style={{
                  position: "absolute",
                  top: 0,
                  left: 0,
                  right: 0,
                  zIndex: 999,
                }}
              >
                <View
                  style={{
                    backgroundColor: "#f1be63",
                    height: statusBarHeight,
                  }}
                >
                  <StatusBar barStyle="dark-content" />
                </View>
              </View>
              <View style={[styles.rootContainer, { paddingBottom: 48 }]}>
                <View style={styles.lowerContainer}>
                  <Text style={styles.primaryText}>You're almost there!</Text>
                  <Avatar
                    rounded
                    size={170}
                    containerStyle={{ alignSelf: "center", marginTop: 24 }}
                    //icon={{ name: "user", type: "font-awesome" }}
                    overlayContainerStyle={{ backgroundColor: "#f1be63" }}
                    source={{
                      uri: "https://cdn.pixabay.com/photo/2019/11/03/20/11/portrait-4599553__340.jpg",
                    }}
                  >
                    <Avatar.Accessory size={20} onPress={avatarPressHandler} />
                  </Avatar>
                  <Text
                    style={[
                      styles.secondaryText,
                      { marginBottom: 8, marginTop: 16 },
                    ]}
                  >
                    Express yourself & customize your avatar
                  </Text>
                  <Input
                    isLabel={true}
                    label="Student Email"
                    placeholder="cce22rnu@uea.ac.uk"
                    onChangeText={handleEmailText}
                    defaultValue={emailText}
                  />
                  <Input
                    isLabel={true}
                    label="Create Password"
                    placeholder="iLoveyoushakila123"
                    onChangeText={handlePasswordText}
                    defaultValue={passwordText}
                  />
                  <Input
                    isLabel={true}
                    label="Confirm Password"
                    placeholder="iLoveyoushakila123"
                  />

                  <Text style={styles.secondaryText}>
                    Now the exciting part - select your top 5 hobbies
                  </Text>

                  <View style={{ alignItems: "center", marginTop: 16 }}>
                    <DropDown
                      data={hobbiesData}
                      onSelect={(selectedItem, index) => {
                        s_context.updateFormData("hobby_1", selectedItem);
                      }}
                    />
                    <DropDown data={hobbiesData} onSelect={(selectedItem, index) => {
                        s_context.updateFormData("hobby_2", selectedItem);
                      }}/>
                    <DropDown data={hobbiesData} onSelect={(selectedItem, index) => {
                        s_context.updateFormData("hobby_3", selectedItem);
                      }}/>
                    <DropDown data={hobbiesData} onSelect={(selectedItem, index) => {
                        s_context.updateFormData("hobby_4", selectedItem);
                      }}/>
                    <DropDown data={hobbiesData} onSelect={(selectedItem, index) => {
                        s_context.updateFormData("hobby_5", selectedItem);
                      }}/>

                    <CustomButton
                      isBorder={true}
                      title="Finish"
                      /*onPress={()=>{navigation.navigate("ConfirmId")}}*/ onPress={
                        FinishBtnHandler
                      }
                    />
                  </View>
                </View>
              </View>
            </ScrollView>
          </HideKeyboard>
        </KeyboardAvoidingView>
  );
}

const styles = StyleSheet.create({
  rootContainer: {
    flex: 1,
    justifyContent: "flex-start",
    alignItems: "center",
    backgroundColor: "#f1be63",
    marginTop: 48,
    backgroundColor: "#f1be63",
  },
  lowerContainer: {
    flex: 1,
    width: "100%",
    alignItems: "center",
  },
  primaryText: {
    color: "white",
    fontSize: 24,
    fontWeight: "bold",
  },
  secondaryText: {
    marginTop: 8,
    color: "white",
    fontSize: 12,
    fontWeight: "bold",
  },
});

export default SignUpForm2;

The state is not updating at all.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459

1 Answers1

3

You need to pass your userDetails state variable to the context, not the initial state value

<SignUpContext.Provider value={{ state: userDetails, updateFormData }}>
  {props.children}
</SignUpContext.Provider>

Passing the initial state object will not see any updates you make.

Also, you should use the functional updates format to dynamically set properties in your state

setDetails((prev) => ({ ...prev, [field]: value }));

Finally, console logging state is a pointless exercise that often gives unexpected results. Just don't do it

Phil
  • 157,677
  • 23
  • 242
  • 245