Reducer代码第一次运行,但是连续两次仅执行Actions代码,而没有执行Reducer代码? | React-Native和Redux

时间:2020-07-29 21:46:53

标签: react-native redux react-redux

我通常会尝试自己解决问题,因此我可以通过检查StackOverflow和Google来从中学到更多,但这已经让我陷入了太久了...

上下文

因此,我正在创建一个React-Native应用程序(没有Expo),并使用redux,redux-thunk和react-redux。

有一项功能,使已登录的用户能够输入或编辑他/她对将来日期的可用性。 因此,我有适当的虚拟数据来设置初始值。

我可以成功地编辑任何日期(使用Availability-day.component.tsx),并在用户配置文件屏幕(profile.component.tsx)上显示更新的可用性。

问题

但是,当我尝试在第一次编辑后再编辑其他任何日期时,它将运行我的代码直到相应的redux动作代码的结尾,但不会执行相应的redux reducer代码(尽管它确实运行了该代码)第一次编辑)...

#TLDR 我可以编辑和更新一次现有的可用性,但是reducer代码不会在连续编辑的情况下执行

有什么想法会导致这种情况以及如何解决?

#FILES

Relevant Files on Google Drive

由于字符限制,我无法在下面的问题或评论中添加所有文件,因此将它们存储在Google云端硬盘中。

// reducer action snippet
export const updateAvailability = (
  userId,
  userAccountType,
  userFirstName,
  userLastName,
  userEmail,
  userPhoneNumber,
  userAvatar,
  userAddress,
  userLocation,
  userBio,
  userFollowers,
  userFollowing,
  userPosts,
  updatedUserAvailability,
  userGender,
  userAge,
) => {
  return async (dispatch) => {
    const date = new Date();
    console.log('ARRIVED AT START OF USERS ACTIONS');
    console.log(updatedUserAvailability);
    try {
      dispatch({
        type: UPDATE_AVAILABILITY,
        profileData: {
          userId: userId,
          userAccountType: userAccountType,
          userFirstName: userFirstName,
          userLastName: userLastName,
          userEmail: userEmail,
          userPhoneNumber: userPhoneNumber,
          userAvatar: userAvatar,
          userAddress: userAddress,
          userLocation: userLocation,
          userBio: userBio,
          userFollowers: userFollowers,
          userFollowing: userFollowing,
          userPosts: userPosts,
          userAvailability: updatedUserAvailability,
          userGender: userGender,
          userAge: userAge,
        },
      });
    } catch (err) {
      // send to custom analytics server
      throw err;
    }
  };
};
// redux reducer snippet
import {
  GET_PROFILES,
  CREATE_PROFILE,
  UPDATE_PROFILE,
  UPDATE_AVAILABILITY,
} from '../actions/users';

const initialState = {
  availableProfiles: PROFILES,
  activeProfile: PROFILES.find((profile) => profile.userId === 'u2'),
  error: null,
};

const usersReducer = (state = initialState, action) => {
  switch (action.type) {
    case UPDATE_AVAILABILITY:
      console.log('ARRIVED AT START REDUCER');
      // Find and update the activeUser Profile.
      const updatingProfileIndex = state.availableProfiles.findIndex(
        (profile) => profile.userId === action.profileData.userId,
      );
      console.log(updatingProfileIndex);
      console.log(action.profileData.userAvailability);

      const updatedAvailabilityProfile = new Profile(
        action.profileData.userId,
        action.profileData.userAccountType,
        action.profileData.userFirstName,
        action.profileData.userLastName,
        action.profileData.userEmail,
        action.profileData.userPhoneNumber,
        action.profileData.userAvatar,
        action.profileData.userAddress,
        action.profileData.userLocation,
        action.profileData.userBio,
        action.profileData.userFollowers,
        action.profileData.userFollowing,
        action.profileData.userPosts,
        action.profileData.userAvailability,
        action.profileData.userGender,
        action.profileData.userAge,
      );

      console.log(updatedAvailabilityProfile);
      console.log(
        'UPDATED AVAILABILITIY PROFILE=' +
          JSON.stringify(updatedAvailabilityProfile),
      );
      // const updatedActiveProfile = [...state.activeProfile];
      // console.log(updatedActiveProfile);
      // updatedActiveProfile[profileIndex] = updatedProfile;
      // console.log(updatedActiveProfile);

      // Update the activeUser Profile in the availableProfiles array.
      const updatingAvailableProfiles = {...state.availableProfiles};
      updatingAvailableProfiles[
        updatingProfileIndex
      ] = updatedAvailabilityProfile;

      // Return the updated profile states
      return {
        ...state,
        availableProfiles: updatingAvailableProfiles,
        activeProfile: updatedAvailabilityProfile,
      };

    default:
      return state;
  }
};

export default usersReducer;
// editing component that sends updated values to redux
import React from 'react';
import {View} from 'react-native';
import {
  Avatar,
  Button,
  StyleService,
  Text,
  TopNavigation,
  TopNavigationAction,
  useStyleSheet,
  useTheme,
  Modal,
  Card,
  Datepicker,
  Spinner,
} from '@ui-kitten/components';
import * as usersActions from '../../store/actions/users';
import {Availability, Profile} from '../../data/profile.model';
import {brandingAppIcon} from '../../assets/images/branding';
import {Timepicker} from '../../components/UI/time-picker.component';
import {AvailabilityDayEditScreenProps} from '../../navigation/profile.navigator';
import {useSelector, connect, useDispatch} from 'react-redux';
import {AppRoute} from '../../navigation/app-routes';

export type AvailabilityDayEditRouteParams = {
  editableAvailability: number;
};

export const AvailabilityDayEditScreen = (
  props: AvailabilityDayEditScreenProps,
): SafeAreaLayoutElement => {
  const {editableAvailability} = props.route.params;
  console.log(editableAvailability);
  const currentUser: Profile = useSelector(
    (state) => state.users.activeProfile,
  );
  console.log(currentUser);

  const [isLoading, setIsLoading] = React.useState(false);
  const [error, setError] = React.useState();

  const [activeUser, setActiveUser] = React.useState<Profile>(currentUser);
  const [userAvailability, setUserAvailability] = React.useState<
    Availability[]
  >(activeUser.userAvailability);

  const [userAvailabilityEditing, setUserAvailabilityEditing] = React.useState<
    Object
  >(activeUser.userAvailability[editableAvailability]);
  const [editDate, setEditDate] = React.useState<Date>(
    userAvailabilityEditing.date,
  );
  const [editDateFrom, setEditDateFrom] = React.useState<Date>(
    userAvailabilityEditing.from,
  );
  const [editDateTo, setEditDateTo] = React.useState<Date>(
    userAvailabilityEditing.to,
  );

  React.useEffect(() => {
    setActiveUser(currentUser);
    setUserAvailability(currentUser.userAvailability);
  }, [currentUser]);

  const dispatch = useDispatch();

  const submitHandler = React.useCallback(async () => {
    // if (!formState.formIsValid) {
    //   Alert.alert('Wrong input!', 'Please check the errors in the form.', [
    //     {text: 'OK'},
    //   ]);
    //   return;
    // }
    setError(null);
    setIsLoading(true);
    try {
      console.log(userAvailabilityEditing);
      // console.log('EDITDATE=' + editDate);
      // console.log('EDITFROM=' + editDateFrom);
      // console.log('EDITTO=' + editDateTo);
      const newUserAvailabilityEditing = {
        ...userAvailabilityEditing,
        from: editDateFrom,
        to: editDateTo,
      };
      console.log(newUserAvailabilityEditing); // CORRECT
      // setEditDate(undefined); // reset editDate
      const updatedUserAvailability = userAvailability.map((availItem) => {
        if (userAvailability.indexOf(availItem) === editableAvailability) {
          return newUserAvailabilityEditing;
        }
        return availItem;
      });
      console.log('UPDATED USER AVAILABILITY BELOW');
      console.log(updatedUserAvailability); // CORRECT
      // console.log(activeUser);

      if (activeUser) {
        await dispatch(
          usersActions.updateAvailability(
            activeUser.userId,
            activeUser.userAccountType,
            activeUser.userFirstName,
            activeUser.userLastName,
            activeUser.userEmail,
            activeUser.userPhoneNumber,
            activeUser.userAvatar,
            activeUser.userAddress,
            activeUser.userLocation,
            activeUser.userBio,
            activeUser.userFollowers,
            activeUser.userFollowing,
            activeUser.userPosts,
            updatedUserAvailability,
            activeUser.userGender,
            activeUser.userAge,
          ),
        );
      }
    } catch (err) {
      setError(err.message);
    }
    setIsLoading(false);
    console.log('Sending User Back to Profile Screen');
    props.navigation.navigate(AppRoute.PROFILE);
  }, [
    props.navigation,
    userAvailabilityEditing,
    editDateFrom,
    editDateTo,
    userAvailability,
    activeUser,
    editableAvailability,
    dispatch,
  ]);

  if (isLoading) {
    return (
      <View style={styles.centeredLoader}>
        <Spinner size="large" />
      </View>
    );
  }

  return (
    <Card
      disabled={true}
      style={styles.container}
      header={() => (
        <View>
          <Avatar style={styles.profileAvatar} source={brandingAppIcon} />
        </View>
      )}>
      <Text>Please edit your availability for this date.</Text>
      <View style={styles.availabilityDayEdit}>
        <Datepicker date={editDate} disabled />
        <Timepicker
          key={'editStartTime'}
          placeholder="Available to start at"
          date={editDateFrom}
          onSelect={(nextTime) => {
            setEditDateFrom(nextTime);
          }}
        />
        <Timepicker
          key={'editEndTime'}
          placeholder="Available until"
          date={editDateTo}
          onSelect={(nextTime) => {
            setEditDateTo(nextTime);
          }}
        />
      </View>
      <Text>{error}</Text>
      <Button onPress={submitHandler}>UPDATE AVAILABILITY</Button>
    </Card>
  );
};

const styles = StyleService.create({
  safeArea: {
    flex: 1,
  },
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    // backgroundColor: 'background-basic-color-2',
  },
  appName: {
    color: 'text-control-color',
  },
  header: {
    flex: 1,
    paddingVertical: 24,
    alignItems: 'center',
    justifyContent: 'center',
  },
  profileAvatar: {
    width: 124,
    height: 124,
    alignSelf: 'center',
    borderRadius: 62,
    marginVertical: 16,
  },
  profileName: {
    zIndex: 1,
  },
  locationContainer: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  location: {
    marginVertical: 8,
  },
  profileButtonsContainer: {
    flexDirection: 'row',
    marginVertical: 32,
    marginHorizontal: 20,
  },
  profileButton: {
    flex: 1,
    marginHorizontal: 4,
  },
  socialsContainer: {
    flexDirection: 'row',
    width: '75%',
    marginVertical: 8,
  },
  profileSocial: {
    flex: 1,
    alignSelf: 'center',
  },
  sectionLabel: {
    marginTop: 16,
    marginBottom: 8,
    marginHorizontal: 16,
  },
  profileDescription: {
    marginHorizontal: 16,
  },
  friendsList: {
    marginHorizontal: 8,
  },
  friendItem: {
    alignItems: 'center',
    marginHorizontal: 8,
  },
  friendName: {
    marginTop: 8,
  },
  postItem: {
    flex: 1,
    aspectRatio: 1.0,
  },
  availabilityContainer: {
    marginLeft: 16,
    marginRight: -16,
  },
  availabilityItemLabel: {
    flex: 1,
    textDecorationLine: 'underline',
  },
  availabilityItemValue: {
    flex: 1,
  },
  availabilityItem: {
    flexDirection: 'row',
    justifyContent: 'flex-start',
    alignItems: 'center',
    marginVertical: 8,
  },
  availabilityItemDate: {
    flex: 3,
  },
  availabilityItemTime: {
    flex: 1,
  },
  availabilityItemButton: {
    // flex: 1,
    marginRight: 30,
  },
  addVenueItem: {
    marginHorizontal: 8,
    alignItems: 'center',
    marginLeft: 0,
  },
  addVenueButton: {
    aspectRatio: 1.0,
    height: 42,
    borderRadius: 24,
    color: 'text-control-color',
    paddingRight: 7,
    // resizeMode: 'contain',
    // width: 50,
    // height: 50,
    // borderRadius: 50,
    // backgroundColor:'black'
  },
  addVenueButtonText: {
    paddingTop: 5,
    fontSize: 13,
  },
  modalBackdrop: {
    backgroundColor: 'rgba(0, 0, 0, 0.5)',
  },
  availabilityDayEdit: {
    flexDirection: 'row',
    paddingVertical: 16,
    justifyContent: 'space-between',
  },
});

connect()(AvailabilityDayEditScreen);

1 个答案:

答案 0 :(得分:0)

和小家伙一起散步回来后,我终于想通了,并想与遇到这个问题的任何人分享错误的原因...:)

我正在尝试创建一个重复的可变状态数组,并最终得到以下一行:

const updatingAvailableProfiles = {...state.availableProfiles};

将其设置回

const updatingAvailableProfiles = state.availableProfiles;

它再次按预期工作。