Reputation: 1272
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
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
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
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
Upvotes: 0
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
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