We're using react-native-web so native and web are in one code base. I have an instance where a user clicks the back button to return to a main page and this should fire a re-query of the backend. We're also using Apollo hooks for queries, useQuery
So far, this works for web but not for native. I tried creating a useEffect hook to check if navigation and specifically navigation.isFocused() like so:
const {
data,
loading: childProfilesLoading,
error: childProfilesError,
refetch: refetchChildProfiles,
} = useQuery(LIST_PROFILES, {
fetchPolicy: 'no-cache',
})
// this method also exists on the previous page
const goBack = () => {
if (history) {
history.goBack()
} else if (navigation) {
navigation.goBack()
}
}
useEffect(() => {
if (navigation?.isFocused()) {
refetchChildProfiles()
}
}, [navigation, refetchChildProfiles])
but this doesn't work. Is there something I'm missing in forcing a refetch on native?
Related
I have a request to implement deep linking in our React Native application whereby clicking a link will take them directly into the installed app. I am able to successfully direct them to the app. However, it must navigate to a certain page.
To address the problem, I use the code below. If there is a better approach to handle the problem, I would appreciate it if you could share it with me!
const useUrl = async () => {
const url = await Linking.getInitialURL();
if (url) {
Navigation.push(componentId, {
component: {
name: 'screen',
},
});
}
};
react-native and react-navigation both handle this as part of a feature set within the "Linking" that they offer. I can't find a way to handle that with React Native Navigation?
For me, I just add path to my stack navigator in react native like this
Product: {
screen: ProductScreen,
path: 'product/:productId'
},
and make sure your web that handle deep link have a similar path in routing. For example https://yourweb.com/product/:productId
And in your screen file, add this
useEffect(() => {
Linking.addEventListener('url', _handleDeepLink)
return () => {
Linking.removeEventListener('url', _handleDeepLink);
}
}
const _handleDeepLink = (event) => {
if (event) {
const route = event.url.replace(/.*?:\/\//g, '')
const id = route.match(/\/([^\/]+)\/?$/)[1];
if (id !== undefined) {
// do your code here if screen just opened via deep link
}
}
}
I have 2 page, Page A (current page) and page B (next page). I am using react-native-router-flux as navigation. When go back to page A from page B (Actions.pop()) i want to refetch usequery so i put code like this in page A or component A
const { loading, data, refetch: refetchData } = useQuery(QUERY_GET_STATUS, {
fetchPolicy: 'network-only',
});
useEffect(() => {
if(refresh){
refetchData();
}
}, [refresh])
variable refresh is redux state has value true and false. Before go back to page A refresh state will be update first into true. but i found the issue that refetch query not working. Do you have any solution to resolve it ?
If you wanna call function every time when screen on front then you this hook
import { useFocusEffect } from '#react-navigation/native';
import React{useCallback} from 'react'
useFocusEffect(
useCallback(() => {
//function
}, [])
);
I had a similar problem with a different package. I'm not totally sure if this might work for you but I think with react-native-router-flux, you have access to currentScene. So you could add an effect that is called whenever the route changes
const currentScene = Actions.currentScene;
useEffect(() => {
if(refresh && currentScene === "whatever-scene-you-are-on"){
refetchData();
}
}, [refresh, currentScene])
As the docs https://reactnavigation.org/docs/en/next/use-focus-effect.html,
"Sometimes we want to run side-effects when a screen is focused. A side effect may involve things like adding an event listener, fetching data, updating document title, etc."
I'm trying to use useFocusEffect to fetch data everytime that the user go to that page.
on my component I have a function which dispatch an action with redux to fetch the data:
const fetchData = ()=>{
dispatch(companyJobsFetch(userDetails.companyId));
};
Actually I'm using useEffect hook to call fetchData(), but I'd like to fetch data everytime that the user go to that page and not only when rendered the first time.
It's not clear from the documentation how to use useFocusEffect and I'm not having success on how to do it.
Any help?
The docs show you how to do it. You need to replace API.subscribe with your own thing:
useFocusEffect(
React.useCallback(() => {
dispatch(companyJobsFetch(userDetails.companyId));
}, [dispatch, companyJobsFetch, userDetails.companyId])
);
For version react navigation 4.x, you can use addEvent listener
useEffect(() => {
if (navigation.isFocused()) {
resetReviews(); // replace with your function
}
}, [navigation.isFocused()]);
OR
useEffect(() => {
const focusListener = navigation.addListener('didFocus', () => {
// The screen is focused
// Call any action
_getBusiness({id: business?.id}); // replace with your function
});
return () => {
// clean up event listener
focusListener.remove();
};
}, []);
For later version 5.x, you can use hooks to achieve this
import { useIsFocused } from '#react-navigation/native';
// ...
function Profile() {
const isFocused = useIsFocused();
return <Text>{isFocused ? 'focused' : 'unfocused'}</Text>;
}
I stuck on Redux Implementation during developing an app using React Native and Redux. I do this for the first time and followed this example.
I've already installed Redux and React Native Navigation. I would like to save the state containing data for countries (the user picked a country and would like to keep the choice by the time when it browses to all screens).
Good. I've created a component that could be seen to all screens like this:
LinksScreen.navigationOptions = {
headerTitle: 'Links',
headerRight: <CountriesPickButton/>,
};
Next, I visualize the button and wait for a change in the component. By default, it should show primary country. Next, the user clicks on the button and it opens a modal where has a dropdown menu. For example, I show you the default fetching a country:
import { connect } from 'react-redux'
import store from '../../redux/countries'
export default class CountriesPick extends Component {
render() {.... // here is the button and modal, etc. It's work.
}
constructor(props, context) {
super(props, context);
this.state = store.getState();
store.subscribe(() => {
this.setState(store.getState());
});
this.defaultCountry(251);
}
async defaultCountry(countryId) {
return fetch(URL)
.then((response) => response.json())
.then((responseJson) => {
for (const key of Object.keys(responseJson.result)) {
// this works for current screen: this.setState({ defaultCountry: responseJson.result[key], selectedCountry: responseJson.result[key].country_id });
store.dispatch({ defaultCountry: responseJson.result[key], selectedCountry: responseJson.result[key].country_id , type: 'countries' });
}
return responseJson.result;
})
.catch((error) => {
console.error(error);
});
state = {
showModal: false,
countries: [],
selectedCountry: 0,
defaultCountry: [],
type: 'countries'
};
}
Without store.dispatch({}) I can change the state with the country but it has not to share between screens. That's because I started with Redux.
Here is the Redux code ():
import { createStore } from 'redux'
const defaultState = {
showModal: false,
countries: [],
selectedCountry: 0,
defaultCountry: [],
type: 'countries'
};
function store(state = defaultState) {
return state;
}
export default createStore(store);
Something is not like it should be. When I invoke store.dispatch({...}) it's not changing the state, it returns the default array. I guess I should use <Provider></Provider> in App.js to catch every change but first, I need to understand what I wrong?
Is it connected at all? In the example that I followed, I did not see connect(). Also, I'm not sure I'm using type properly.
Thank you in advance.
Problems here are the following:
Example on the link you provided is bad to say the least. Do not follow it
You said to be using react-native-navigation, but the code you provided comes from react-navigation. I suggest using the latter, especially for starters
Your createStore code is not going to work, as reducer for the store should be a function of state and action
With that being said, you should definitely see Basic Tutorial of redux with examples. You will almost never have to do store.getState() or store.dispatch() while using react with redux, as react-reduxpackage (included in the tutorial I linked) will do this for you. You will instead declare dependency between your store state and props your component receives
I have the function
onPress = (store) => {
//store.flipState();
this.props.navigation.navigate('anotherScreen');
console.log('hi');
}
If I run it as above the navigation works.
If I uncomment the store.flipState() line the state changes but the navigation doesn't work (the screen just refreshes).
The console.log works in both cases.
How can I change the state and navigate at the same time?
I use Unstated and React Navigation in React Native.
Thank you.
I know this is really old, but what if you pass the navigate action to flipState
const {navigation: {navigate}} = this.props
store.flipState(navigate('anotherScreen'))
then, in flipState, when you call setState, pass the navigate as the success action callback
flipState = (callback) => {
this.setState((state) => {
return { flippedState: !state.flippedState };
}, callback);
};