Hyejung
Hyejung

Reputation: 1272

How to refresh page in React native?

My dev env is

"react": "17.0.1", "react-dom": "17.0.1", "react-hook-form": "^7.22.1", "react-native": "^0.64.3",

I'd like to refresh my page once I delete my comment. Mostly in this case, I've used navigation.goBack() or navigation.navigate("same page") like below.

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

But the problem is Comments page has Flatlist with data getting from the previous page. On this page, I can't pass same data set ({route}) to Comments page.

So It refreshes my page but with no data, which means empty page. I don't want that. I just refresh my page as deleting only one comment.

When I searched on Internet, people recommend window.location.reload() But when I use it instead of navigation, it gives me error saying that:

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

Can't React native use window.location.reload()? As far as I know, It doesn't need any installation or import.

How can I use window.location.reload()? Otherwise, which way can I refresh my page?


Srimurugan Sri taught me that React can't use window ;) thanks. So as he recommended I tried to use extraData. as far as I understand, it watch any change on {data} part. And if some change detected, automatically re-render flatlist.

So I made useState and added extraData as below.

 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>
  );

But it still doesn't refresh my page. Can you teach me more?

CommentRow page

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>
  );
}

Upvotes: 3

Views: 40254

Answers (5)

Mykyta Chernenko
Mykyta Chernenko

Reputation: 403

Unfortunately, there is no such concept as "reload" in React Native. Once a Route is "mounted" it won't remount even if you navigate from and back to the component.

So I use the following idea to "reload" the component once I navigate to it from another one and when I want to reload the component on the refresh pull gesture

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>
  );
}

Upvotes: 2

TheRealMikeD
TheRealMikeD

Reputation: 174

If you really want to force a re-render on a screen, one way that you can do so is to use the useFocusEffect hook. It will fire each time that the screen gains focus.

In the OP's case, it sounds like the ask is to re-render the current screen while the user is still on it. In this case, you could update an item of state to force a re-render. The state item itself doesn't have to be displayed anywhere on the screen:

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());
}

As others have noted, forcing a re-render is generally not recommended, but if you do have a special case where you really want to re-render, you can use one of these techniques to get the job done.

Upvotes: 0

Engazan
Engazan

Reputation: 525

i m not sure why you r doing this way ( react is reactive framework so use it ) but you can pass props to your SCREEN

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

data => comments is just name

then inside your "Comments" ( CommentsScreeen ), just call "setData" from route params like

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))

there are maybe only 2 problems with my example, but 1st can be fixed, 2nd ignored

  1. st both screens get rerender ( with is performance problem )
  1. you get warrning cuz u sending React.Dispatch, with is not passible to serialize but its not WRONG its just warrning in console ...

Upvotes: 0

Srimurugan Subramanian
Srimurugan Subramanian

Reputation: 188

Since your source of data is from route.params.comments. Flatlist not will not refresh data Since you have extraData as SelectedID.

Please have your data in state and pass the same state to 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

Upvotes: 2

Srimurugan Subramanian
Srimurugan Subramanian

Reputation: 188

If you want to refresh the data of Flatlist, you can Use the extraData property on your FlatList component instead of changing route.

we can't use window.location.reload() in React native.

Upvotes: 3

Related Questions