0

In my app, I fetch users data from the server inside the useEffect hook and set the initialState of the useReducer. When action dispatch happens on text input change, the initialState resets instead of updating thus I can't type a word inside the input. Can someone figure out the problem, please? I'm fairly new to react reducers. I have attached the relevant codes. Thanks.

EditProfile.js

const EditProfile = ({ navigation, route }) => {
  const userid = route.params.userid;
  const { user } = React.useContext(AuthContext);
  const [userData, setUserData] = React.useState(null);

  const initialState = {
    name: userData ? (userData.name ? userData.name : "") : "",
    dob: userData ? (userData.dob ? userData.dob.toDate() : "") : "",
    phone: userData ? (userData.phone ? userData.phone : "") : "",
    location: userData ? (userData.location ? userData.location : "") : "",
    caption: userData ? (userData.caption ? userData.caption : "") : "",
  };

  React.useEffect(() => {
    async function fetchData() {
      const response = await getUserData(userid);
      setUserData(response);
    }
    fetchData();
  }, []);

  const reducer = (state, action) => {
    switch (action.type) {
      case "nameInputChange":
        return {
          ...state,
          name: action.name,
        };
      case "dobInputChange":
        return {
          ...state,
          dob: action.dob,
        };
      case "phoneInputChange":
        return {
          ...state,
          phone: action.phone,
        };
      case "locationInputChange":
        return {
          ...state,
          location: action.location,
        };
      case "captionInputChange":
        return {
          ...state,
          caption: action.caption,
        };
    }
  };

  const [data, dispatch] = React.useReducer(reducer, initialState);

  const nameInputChange = (value) => {
    dispatch({
      type: "nameInputChange",
      name: value,
    });
    console.log("Name: ", initialState.name);
  };

  const dobInputChange = (date) => {
    dispatch({
      type: "dobInputChange",
      dob: date,
    });
  };

  const phoneInputChange = (value) => {
    dispatch({
      type: "phoneInputChange",
      phone: value,
    });
  };

  const locationInputChange = (value) => {
    dispatch({
      type: "locationInputChange",
      location: value,
    });
  };

  const captionInputChange = (value) => {
    dispatch({
      type: "captionInputChange",
      caption: value,
    });
  };

  return (
    <View>
      <FlatList
        showsVerticalScrollIndicator={false}
        ListHeaderComponent={() => (
          <View>
            <TouchableOpacity>
              <Image
                source={require("../assets/images/profile.jpg")}
                style={{ width: "98%", height: "98%", borderRadius: 59 }}
              />
              <View>
                <Entypo name="camera" color="#8000e3" size={18} />
              </View>
            </TouchableOpacity>
            <View>
              <VerticalNameInput
                type="name"
                label="Full Name"
                placeholder="Full name"
                color="#9798ac"
                placeholder="enter your full name"
                onChangeText={(value) => nameInputChange(value)}
                value={initialState.name}
              />
              <VerticalDateInput
                label="Date of Birth"
                color="#9798ac"
                dobInputChange={dobInputChange}
                initialState={initialState}
              />
            </View>
            <View>
              <VerticalNameInput
                type="mobile"
                label="Mobile"
                color="#9798ac"
                placeholder="mobile number"
                onChangeText={(value) => phoneInputChange(value)}
                value={initialState.phone}
              />
              <VerticalNameInput
                type="location"
                label="Location"
                color="#9798ac"
                placeholder="city and country"
                onChangeText={(value) => locationInputChange(value)}
                value={initialState.location}
              />
            </View>
            <View>
              <VerticalNameInput
                type="caption"
                label="Profile Caption"
                color="#9798ac"
                placeholder="enter about yourself"
                onChangeText={(value) => captionInputChange(value)}
                value={initialState.caption}
              />
            </View>
          </View>
        )}
      />
      <View style={{ position: "relative", top: -90, left: 200 }}>
        <FloatingAction
          onPressMain={() => {
            updateUser(userid, userData);
          }}
          floatingIcon={<Entypo name="check" size={28} color="#fff" />}
        />
      </View>
    </View>
  );
};

export default EditProfile;

VerticalNameInput.js

const VerticalNameInput = ({ label, color, placeholder, type, ...rest }) => {
  return (
    <View>
      <Text>
        {label}
      </Text>
      <View>
        <View>
          {type === "name" ? (
            <AntDesign name="user" color="#000" size={15} />
          ) : type === "mobile" ? (
            <AntDesign name="mobile1" color="#000" size={15} />
          ) : type === "location" ? (
            <EvilIcons name="location" color="#000" size={20} />
          ) : type === "caption" ? (
            <Ionicons
              name="information-circle-outline"
              color="#000"
              size={18}
            />
          ) : null}
        </View>
        <TextInput
          style={{ width: "85%", height: "100%" }}
          numberOfLines={1}
          placeholder={placeholder}
          placeholderTextColor={color}
          {...rest}
        />
      </View>
    </View>
  );
};

export default VerticalNameInput;

VerticalDateInput.js

const VerticalDateInput = ({ label, color, dobInputChange, initialState }) => {
  const [date, setDate] = React.useState(new Date());
  const [open, setOpen] = React.useState(false);

  return (
    <View>
      <Text>
        {label}
      </Text>
      <View>
        <View>
          <AntDesign name="calendar" color="#000" size={15} />
        </View>
        <View>
          <Text style={{ marginLeft: 10 }}>
            {initialState.dob
              ? initialState.dob.toDateString()
              : new Date().toDateString()}
          </Text>
          <TouchableOpacity
            style={{ marginRight: 10 }}
            onPress={() => setOpen(true)}
          >
            <AntDesign name="caretdown" color="#000" size={12} />
          </TouchableOpacity>
        </View>
        <DatePicker
          maximumDate={new Date()}
          mode="date"
          modal
          open={open}
          date={initialState.dob ? initialState.dob : date}
          onConfirm={(date) => {
            setOpen(false);
            setDate(date);
            dobInputChange(date);
          }}
          onCancel={() => {
            setOpen(false);
          }}
        />
      </View>
    </View>
  );
};

export default VerticalDateInput;
Shoaib Khan
  • 1,020
  • 1
  • 5
  • 18
CleanCodeOnline
  • 107
  • 2
  • 11

1 Answers1

0

Try add "default" case return current state in your reducer. It might happen that you dispatch some unknown action, and reducer return undefined as a result.

const reducer = (state = initialState, action) => {
      switch (action.type) {
        default:
          // If this reducer doesn't recognize the action type, or doesn't
          // care about this specific action, return the existing state unchanged
          return state
  }
}
Kirill Novikov
  • 2,576
  • 4
  • 20
  • 33
Doppio
  • 2,018
  • 12
  • 11