如何在React Native中刷新页面?

问题描述 投票:0回答:5

我的开发环境是

“反应”:“17.0.1”, “反应-dom”:“17.0.1”, "react-hook-form": "^7.22.1", “反应本机”:“^0.64.3”,

删除评论后我想刷新我的页面。 大多数情况下,我使用了

navigation.goBack()
navigation.navigate("same page")
,如下所示。

  const onDeleteClick = () => {
    deleteCommentMutation();
    navigation.navigate("Comments");
  };

但问题是评论页面有 Flatlist,其中的数据是从上一页获取的。 在此页面上,我无法将相同的数据集({route})传递到评论页面。

所以它刷新了我的页面,但没有数据,这意味着空页面。 我不想要这样。我只是刷新页面,只删除一条评论。

我在网上搜索时,人们推荐

window.location.reload()
但是当我使用它而不是导航时,它会给我错误提示:

TypeError: undefined is not an object (evaluating 'window.location.reload')

at node_modules/react-native/Libraries/Core/ExceptionsManager.js:104:6 in reportException
at node_modules/react-native/Libraries/Core/ExceptionsManager.js:172:19 in handleException
at node_modules/react-native/Libraries/Core/setUpErrorHandling.js:24:6 in handleError
at node_modules/expo-error-recovery/build/ErrorRecovery.fx.js:12:21 in ErrorUtils.setGlobalHandler$argument_0

React原生不能使用window.location.reload()吗? 据我所知,它不需要任何安装或导入。

如何使用window.location.reload()? 否则,我可以通过什么方式刷新我的页面?


Srimurugan Sri 教我 React 不能使用窗口;)谢谢。 因此,按照他的建议,我尝试使用 extraData。 据我了解,它会观察 {data} 部分的任何变化。 如果检测到某些更改,则会自动重新渲染平面列表。

所以我制作了

useState
并添加了
extraData
,如下所示。

 const [selectedId, setSelectedId] = useState(null);
  return (
    <Container>
      <CommentBox>
        <FlatList
          keyboardDismissMode={true}
          showsVerticalScrollIndicator={false}
          data={route?.params?.comments}
          keyExtractor={(comment) => "" + comment.id}
          renderItem={renderComment}
          extraData={selectedId}
        />
      </CommentBox>
    </Container>
  );

但它仍然没有刷新我的页面。 你能教我更多吗?

评论行页面

export default function CommentRow({
  id,
  user,
  payload,
  isMine,
  createdAt,
  updatedAt,
  commentNumber,
  photoId,
}) {
  const createdDate = new Date(+createdAt);
  const date = createdDate.toISOString().substring(0, 10);
  const updateDeleteComment = (cache, result) => {
    const {
      data: {
        deleteComment: { ok, error },
      },
    } = result;
    if (ok) {
      cache.evict({ id: `Comment:${id}` });
      cache.modify({
        id: `Photo:${photoId}`,
        fields: {
          commentNumber(prev) {
            return prev - 1;
          },
        },
      });
    }
  };

  const [deleteCommentMutation] = useMutation(DELETE_COMMENT_MUTATION, {
    variables: {
      id,
    },
    update: updateDeleteComment,
  });
  const onDeleteClick = () => {
    deleteCommentMutation();
  };
  return (
    <Container>
      <CommentContainer>
        <UserImage source={{ uri: user.avatar }} />
        <TextBox>
          <Header>
            <Username>{user.username}</Username>
            <CreatedTime>{date}</CreatedTime>
          </Header>
          <CommentText>{payload}</CommentText>
        </TextBox>
      </CommentContainer>
      {isMine ? (
        <WriteContainer>
          <TouchableOpacity>
            <WriteComment>수정</WriteComment>
          </TouchableOpacity>
          <TouchableOpacity onPress={onDeleteClick}>
            <WriteComment>삭제</WriteComment>
          </TouchableOpacity>
        </WriteContainer>
      ) : null}
    </Container>
  );
}
react-native
5个回答
3
投票

如果你想刷新Flatlist的数据,你可以使用FlatList组件上的extraData属性而不是改变路由。

我们不能在 React Native 中使用

window.location.reload()


2
投票

不幸的是,React Native 中没有“重新加载”这样的概念。一旦“安装”了路线,即使您往返于组件,它也不会重新安装。

因此,当我从另一个组件导航到该组件时,以及当我想通过刷新拉动手势重新加载该组件时,我使用以下想法来“重新加载”该组件

export class Props {
 refreshTimeStamp: string | undefined 
};
export class MainParamList {
  Main: Props
}

export default function ({
  route,
  navigation,
}: NativeStackScreenProps<MainParamList, 'Main'>) {
  const [data, setData] = setState<string>('')
  const refreshData = () => setData('result')

  useEffect(() => {
    if (route.params?.refreshTimeStamp) {
      void refreshData();
    }
  }, [route.params]);


  return (      
      <ScrollView
        contentContainerStyle={{
          flexGrow: 1,
          backgroundColor: 'white',
        }}
        refreshControl: {
          <RefreshControl
            refreshing={false}
            onRefresh={() => {
              navigation.navigate('Main', { refreshTimeStamp: new 
  Date().toISOString() });
            }}
            style={{ flexGrow: 1 }}
          />
        }
      >
      {data}
    </ScrollView>
  );
}

2
投票

因为您的数据来源来自

route.params.comments
。 Flatlist 不会刷新数据,因为您有 extraData 作为 SelectedID。

请保存您的数据状态并将相同的状态传递给 extraData。

import React,{useState, useEffect} from 'react';
useEffect( () => {
  const [comments, setComments] = useState(route?.params?.comments); 
  // update the comments after deleting using setComments() syntax;
},[])    
//Both data & extraData is comments
const [selectedId, setSelectedId] = useState(null);

  return (
    <Container>
      <CommentBox>
        <FlatList
          keyboardDismissMode={true}
          showsVerticalScrollIndicator={false}
          data={comments} 
          keyExtractor={(comment) => "" + comment.id}
          renderItem={renderComment}
          extraData={comments}
        />
      </CommentBox>
    </Container>
  );
  // You cannot use window.location.reload() in react native, but you can use in Web development

0
投票

我不知道你为什么这样做(反应是反应式框架,所以使用它),但你可以将道具传递到你的屏幕

navigation.navigate('Comments', {setData: setData, data: data});

数据 => 评论只是名称

然后在你的“评论”(CommentsScreen)中,只需从路由参数中调用“setData”,如

interface CommentsScreenRouteProps {
    key: string,
    name: string,
    params: {
        data,
        setData: React.Dispatch<any>,
    },
    path: string,
}
...
const route = useRoute<CommentsScreenRouteProps>();
...

route.params.setData(route.params.data.filter(() => true))

我的示例可能只有两个问题,但第一个可以修复,第二个被忽略

  1. 两个屏幕都会重新渲染(存在性能问题)
  1. 你会收到警告,因为你发送了 React.Dispatch,无法序列化,但它不是错误的,它只是在控制台中发出警告......

0
投票

如果您确实想在屏幕上强制重新渲染,可以使用的一种方法是使用 useFocusEffect 钩子。每次屏幕获得焦点时它都会触发。

在OP的情况下,听起来好像要求在用户仍在屏幕上时重新渲染当前屏幕。在这种情况下,您可以更新状态项以强制重新渲染。状态项本身不必显示在屏幕上的任何位置:

const [dummyState, setDummyState] = useState(0);

// Connect this function to the onPress prop of a Button as an example.
// For the OP's case, you could add it into the code that deletes the comment, 
// directly after the comment is deleted.
function btnHandler() {
    // This will force a re-render.
    setDummyState(Date.now());
}

正如其他人所指出的,通常不建议强制重新渲染,但如果您确实有特殊情况确实想要重新渲染,则可以使用其中一种技术来完成工作。

© www.soinside.com 2019 - 2024. All rights reserved.