reactjs 父状态变量更改时,子组件不会重新呈现

brc7rcf0  于 2023-04-05  发布在  React
关注(0)|答案(2)|浏览(132)

我是React Native的新手,我正在努力让一个子视图在应该更新/重新渲染的时候更新/重新渲染。代码粘贴在下面。UserProfile包含一个带有Posts,Diet,Workouts和Gallery的标签栏。UserProfileGalleryView包含一个图像网格。单击图像时,应该打开一个显示图像的模态视图,但目前它只会在我单击图像时显示,点击posts/diet/workout,然后点击返回到画廊。一旦我点击返回到画廊,模态视图显示,关闭按钮并没有关闭它。很明显,我的状态没有得到正确的管理。我已经尝试使用useEffect和useContext无效。任何帮助都将不胜感激。
UserProfile(父组件):

import { Auth } from "aws-amplify";
import React, { useEffect } from "react";
import {
  View,
  SafeAreaView,
  Text,
  StyleSheet,
  Pressable,
  Image,
  TurboModuleRegistry,
} from "react-native";
import UserProfileWorkoutsView from "./UserProfileWorkoutsView";
import UserProfileDietView from "./UserProfileDietView";
import UserProfileGalleryView from "./UserProfileGalleryView";
import UserProfilePostsView from "./UserProfilePostsView";

function UserProfile({ route, navigation }) {
  const [currentView, setCurrentView] = React.useState(UserProfilePostsView);
  const userInfo = route.params.userInfo;

  const onSettingsPressed = async (data) => {
    navigation.navigate("Settings");
  };

  const [modalVisible, setModalVisible] = React.useState(false);
  const [selectedImage, setSelectedImage] = React.useState(null);

  const toggleModalView = () => {
    setModalVisible(!modalVisible);
  };

  const updateSelectedImage = (item) => {
    setSelectedImage(item);
  };

  const onPress = (data) => {
    switch (data["_targetInst"]["alternate"]["memoizedProps"]["name"]) {
      case "postsButton":
        setCurrentView(UserProfilePostsView);
        return;
      case "workoutsButton":
        setCurrentView(UserProfileWorkoutsView);
        return;
      case "dietButton":
        setCurrentView(UserProfileDietView);
        return;
      case "galleryButton":
        setCurrentView(() => (
          <UserProfileGalleryView
            toggleModalView={toggleModalView}
            updateSelectedImage={updateSelectedImage}
            modalVisible={modalVisible}
            selectedImage={selectedImage}
          />
        ));
        return;
    }
  };

  return (
    <SafeAreaView
      style={styles.container}
      contentInsetAdjustmentBehavior="never"
    >
      <View style={styles.profileHeader}>
        <Pressable style={styles.profilePic} onPress={() => {}}>
          <Image
            style={{ width: 100, height: 100, resizeMode: "contain" }}
            source={require("./assets/profile_pic_temp.png")}
          />
        </Pressable>
        <View>
          <Text style={{ fontWeight: "bold" }}>
            STREAK {userInfo.userStreak} 🔥
          </Text>
          <Text style={{ fontWeight: "bold", fontSize: 24 }}>
            {userInfo.userFirstLastName}
          </Text>
          <Text style={{}}>{userInfo.userBio}</Text>
        </View>
      </View>

      <View style={styles.tabBar}>
        <Pressable
          style={styles.tabBarIcon}
          name="postsButton"
          onPress={onPress}
        >
          <Image
            style={styles.tabBarIcon}
            source={require("./assets/posts_icon.png")}
          />
        </Pressable>
        <Pressable
          style={styles.tabBarIcon}
          name="workoutsButton"
          onPress={onPress}
        >
          <Image
            style={styles.tabBarIcon}
            source={require("./assets/barbell-hand.png")}
          />
        </Pressable>
        <Pressable
          style={styles.tabBarIcon}
          name="dietButton"
          onPress={onPress}
        >
          <Image
            style={styles.tabBarIcon}
            source={require("./assets/diet_icon.png")}
          />
        </Pressable>
        <Pressable
          style={styles.tabBarIcon}
          name="galleryButton"
          onPress={onPress}
        >
          <Image
            style={styles.tabBarIcon}
            source={require("./assets/gallery_icon.png")}
          />
        </Pressable>
      </View>

      <Pressable style={styles.settingsButton} onPress={onSettingsPressed}>
        <Image
          style={{ width: 40, height: 40, resizeMode: "contain" }}
          source={require("./assets/settings_cog.png")}
        />
      </Pressable>

      <View style={styles.contentContainer}>{currentView}</View>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "dodgerblue",
    alignItems: "center",
    justifyContent: "flex-start",
  },
  settingsButton: {
    position: "absolute",
    alignSelf: "flex-end",
    height: 40,
    width: 40,
    marginTop: 60,
    paddingRight: 60,
  },
  profileHeader: {
    alignItems: "flex-start",
    flexDirection: "row",
    marginTop: 20,
    width: "100%",
    marginHorizontal: 80,
  },
  profilePic: {
    alignSelf: "flex-start",
    marginRight: 10,
    marginLeft: 10,
  },
  tabBar: {
    height: 40,
    flexDirection: "row",
    justifyContent: "space-between",
    width: "100%",
    backgroundColor: "lightblue",
    alignItems: "center",
    marginTop: 20,
  },
  tabBarIcon: {
    flex: 1,
    alignSelf: "center",
    width: 30,
    height: 30,
    resizeMode: "contain",
  },
  contentContainer: {
    flex: 1,
    width: "100%",
    //backgroundColor: "white",
  },
});

export default UserProfile;

UserProfileGalleryView(子组件):

import React, { useEffect } from "react";
import {
  StyleSheet,
  Image,
  FlatList,
  Dimensions,
  Modal,
  TouchableOpacity,
  View,
} from "react-native";

//temp for displaying purposes
const userImages = new Array(17).fill("https://picsum.photos/400");
const screenWidth = Dimensions.get("window").width;
const numColumns = 3;
const tileSize = screenWidth / numColumns;

function renderItem({ item, props }) {
  //Single item of Grid
  return (
    <TouchableOpacity
      key={item.id}
      style={{ height: tileSize, width: tileSize }}
      onPress={() => {
        props.toggleModalView();
        props.updateSelectedImage(item);
      }}
    >
      <Image resizeMode="cover" style={{ flex: 1 }} source={{ uri: item }} />
    </TouchableOpacity>
  );
}

function UserProfileGalleryView(props) {

  if (props.modalVisible) {
    //Modal to show full image with close button
    return (
      <Modal
        transparent={false}
        animationType={"fade"}
        visible={props.modalVisible}
        onRequestClose={() => {
          props.toggleModalView();
        }}
      >
        <View style={styles.modelStyle}>
          <Image
            style={styles.fullImageStyle}
            source={{ uri: props.selectedImage }}
          />
          <TouchableOpacity
            activeOpacity={0.5}
            style={styles.closeButtonStyle}
            onPress={() => {
              props.toggleModalView();
            }}
          >
            <Image
              source={{
                uri: "https://cdn2.iconfinder.com/data/icons/media-controls-5/100/close-1024.png",
              }}
              style={{ width: 25, height: 25, marginTop: 16 }}
            />
          </TouchableOpacity>
        </View>
      </Modal>
    );
  } else {
    return (
      <FlatList
        data={userImages}
        renderItem={({ item }) =>
          renderItem({
            item,
            props,
          })
        }
        numColumns={3}
      />
    );
  }
}

const styles = StyleSheet.create({
  photoGrid: {
    flex: 3,
    marginHorizontal: "auto",
    backgroundColor: "dodgerblue",
  },
  row: {
    flexDirection: "row",
  },
  col: {
    backgroundColor: "dodgerblue",
    borderColor: "#fff",
    borderWidth: 1,
    flex: 3,
  },
  galleryImage: {
    width: "100%",
    resizeMode: "contain",
  },

  containerStyle: {
    justifyContent: "center",
    flex: 1,
    marginTop: 20,
  },
  fullImageStyle: {
    justifyContent: "center",
    alignItems: "center",
    height: "100%",
    width: "98%",
    resizeMode: "contain",
  },
  modelStyle: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: "rgba(0,0,0,0.4)",
  },
  closeButtonStyle: {
    width: 25,
    height: 25,
    top: 50,
    right: 20,
    position: "absolute",
  },
});

export default UserProfileGalleryView;
3pmvbmvn

3pmvbmvn1#

为我的评论提供适当的答案/解释。
您可以使用onPress函数为currentView设置一个字符串,并根据该状态渲染组件。

function UserProfile({ route, navigation }) {
  const [currentView, setCurrentView] = React.useState("posts");

  // ...

  const onPress = (newView) => {
    setCurrentView(newView);
  };

  return (
    <SafeAreaView
      style={styles.container}
      contentInsetAdjustmentBehavior="never"
    >
      ...

      <View style={styles.tabBar}>
        <Pressable
          style={styles.tabBarIcon}
          onPress={() => setCurrentView("posts")}
        >
          <Image
            style={styles.tabBarIcon}
            source={require("./assets/posts_icon.png")}
          />
        </Pressable>
        <Pressable
          style={styles.tabBarIcon}
          onPress={() => onPress("workouts")}
        >
          <Image
            style={styles.tabBarIcon}
            source={require("./assets/barbell-hand.png")}
          />
        </Pressable>
        <Pressable style={styles.tabBarIcon} onPress={() => onPress("diet")}>
          <Image
            style={styles.tabBarIcon}
            source={require("./assets/diet_icon.png")}
          />
        </Pressable>
        <Pressable style={styles.tabBarIcon} onPress={() => onPress("gallery")}>
          <Image
            style={styles.tabBarIcon}
            source={require("./assets/gallery_icon.png")}
          />
        </Pressable>
      </View>

      <Pressable style={styles.settingsButton} onPress={onSettingsPressed}>
        <Image
          style={{ width: 40, height: 40, resizeMode: "contain" }}
          source={require("./assets/settings_cog.png")}
        />
      </Pressable>
      <View style={styles.contentContainer}>
        {currentView === "posts" ? (
          <UserProfilePostsView />
        ) : currentView === "workouts" ? (
          <UserProfileWorkoutsView />
        ) : currentView === "diet" ? (
          <UserProfileDietView />
        ) : currentView === "gallery" ? (
          <UserProfileGalleryView
            toggleModalView={toggleModalView}
            updateSelectedImage={updateSelectedImage}
            modalVisible={modalVisible}
            selectedImage={selectedImage}
          />
        ) : null}
      </View>
    </SafeAreaView>
  );
}
bttbmeg0

bttbmeg02#

我同意上面的评论,不建议将组件存储在状态中。
也就是说,我相信你遇到的问题是在你的onPress事件中,当你设置当前视图时,你没有为你的gallery模态翻转模态状态。所以视图被设置了,但是modalVisible = false的状态值被传递给你的子组件,模态没有显示。
我想这会解决你的问题:

const onPress = (data) => {
    switch (data["_targetInst"]["alternate"]["memoizedProps"]["name"]) {
      case "postsButton":
        setCurrentView(UserProfilePostsView);
        return;
      case "workoutsButton":
        setCurrentView(UserProfileWorkoutsView);
        return;
      case "dietButton":
        setCurrentView(UserProfileDietView);
        return;
      case "galleryButton":
        setModalVisible(true)     <------- Add this line
        setCurrentView(() => (
          <UserProfileGalleryView
            toggleModalView={toggleModalView}
            updateSelectedImage={updateSelectedImage}
            modalVisible={modalVisible}
            selectedImage={selectedImage}
          />
        ));
        return;
    }
  };

添加setModalVisible(true)这一行应该会在你第一次设置视图时显示模态,但允许你像当前的设置一样隐藏它。

相关问题