i am getting this error mutiple time
You started loading the font "Poppins_400Regular", but used it before it finished loading. You need to wait for Font.loadAsync to complete before using the font.
when run the code
In your apps entry point, usually App.jsx you can render null or a loading state whilst the fonts for your app load, and then once the loadAsync finishes you render your app, something along the lines of:
// App.jsx, or whatever your entry point is
const App = () => {
const [fontLoaded, setFontLoaded] = React.useState(false)
React.useEffect(() => {
Font.loadAsync({
"Poppins_400Regular": require("../path/to/your/font"),
})
.then(() => {
setFontLoaded(true)
})
}, [])
if (!fontLoaded) return null
return (
// All of your normal app ui
)
}
Related
I have an expo app that loads a provider:
export const AppProvider = ({ children }: { children: ReactNode }) => {
console.log('Hello from app provider!!');
const alertsBottomSheetRef = useRef<BottomSheetModal>(null);
const dismissAlert = useCallback(() => {
alertsBottomSheetRef.current?.close();
}, []);
const values = {
alertsBottomSheetRef,
dismissAlert,
};
// >>>>> return <AppContext.Provider value={values}>{children}</AppContext.Provider>;
};
If I load the app with the last line commented, I can see the console.log. I can also see any changes I made to the console.log.
However, When I uncomment that last line, I don't get any console.logs.
Any thoughts why?
What I think why its not working because the AppContext.Provider is a context provider, and it does not log anything to the console. The purpose of a context provider is to provide data to components that are descendants of the provider. It does not render anything to the screen and does not log anything to the console.
The issue was that I started the server with expo start and not expo start --dev-client. console logs now appear as expected.
I am writing an app with Expo that uses expo-location to track the location of a user in the background. I would like to use hooks (states, useEffect...) when my app is in the background. At the moment the background tracking code looks like that
export default function BackgroundLocationHook() {
[...]
const [position, setPosition] = useState(null);
const [newLocation, setNewLocation] = useState(null) ;
TaskManager.defineTask(LOCATION_TASK_NAME, async ({ data, error }) => {
if (error) {
console.error(error);
return;
}
if (data) {
// Extract location coordinates from data
const { locations } = data;
const location = locations[0];
if (location) {
console.log("Location in background", location.coords);
}
}
setPosition(location.coords);
});
[...]
return [position];
}
But it is a bit hacky as the geolocation_tracking task shares some states with the
I would also like to play some sounds when I am close to a some location even when my app is in the background. I plan to do it with useEffect like that:
useEffect(() => {
const requestPermissions = async () => {
if(shouldPlaySound(newLocation)){
playSound()
}
};
requestPermissions();
}, [newLocation]);
This works when my app is in the foreground but I heard that react hooks such as states, and useEffect do not work when the app is in the background. So my question is what is the alternative to make sure I still have a sound being played when my app is in the background and if it is possible to have hooks working even when the app is in the background.
I see you want to perform some task in the background when you pass a specific location,
With the expo location, we can achieve this implementation.
You can add fencing to your desired location and when the device will enter the fencing area or exits from the fencing area you will get an event to handle some tasks and you are also able to listen to the event in the background with the Expo Task manager.
You need to follow the steps to achieve this.
Define a task using Expo Task Manager outside the react life cycle,
and read the official documentation for API usage. Expo Task Manager
Take the necessary permissions to access the location in the background, and start geofencing with your component. Expo Location
Stop the fencing listener using stopGeofencingAsync from expo-location when it is not needed anymore.
Now you will get events every time you enter or exit from the specified location in startGeofencingAsync until you stop using the stopGeofencingAsync method.
Hope this will help you achieve your desired input.
to run a task in the background you can check any of these library.
react-native-background-actions
react-native-background-timer
this is some example code
import BackgroundTimer from 'react-native-background-timer';
// Start a timer that runs continuous after X milliseconds
const intervalId = BackgroundTimer.setInterval(() => {
// this will be executed every 200 ms
// even when app is the background
console.log('tic');
}, 200);
// Cancel the timer when you are done with it
BackgroundTimer.clearInterval(intervalId);
// Start a timer that runs once after X milliseconds
const timeoutId = BackgroundTimer.setTimeout(() => {
// this will be executed once after 10 seconds
// even when app is the background
console.log('tac');
}, 10000);
// Cancel the timeout if necessary
BackgroundTimer.clearTimeout(timeoutId);
this is another example of this code
import BackgroundService from 'react-native-background-actions';
const sleep = (time) => new Promise((resolve) => setTimeout(() => resolve(), time));
// You can do anything in your task such as network requests, timers and so on,
// as long as it doesn't touch UI. Once your task completes (i.e. the promise is resolved),
// React Native will go into "paused" mode (unless there are other tasks running,
// or there is a foreground app).
const veryIntensiveTask = async (taskDataArguments) => {
// Example of an infinite loop task
const { delay } = taskDataArguments;
await new Promise( async (resolve) => {
for (let i = 0; BackgroundService.isRunning(); i++) {
console.log(i);
await sleep(delay);
}
});
};
const options = {
taskName: 'Example',
taskTitle: 'ExampleTask title',
taskDesc: 'ExampleTask description',
taskIcon: {
name: 'ic_launcher',
type: 'mipmap',
},
color: '#ff00ff',
linkingURI: 'yourSchemeHere://chat/jane', // See Deep Linking for more info
parameters: {
delay: 1000,
},
};
await BackgroundService.start(veryIntensiveTask, options);
await BackgroundService.updateNotification({taskDesc: 'New ExampleTask description'}); // Only Android, iOS will ignore this call
// iOS will also run everything here in the background until .stop() is called
await BackgroundService.stop();
A third solution for android is the headlessjs that only works on android
you can tak help from this
I'm new in react native so I can't figure out how to add an API call inside SplashScreen in react -native app. The context - I'm building a react-native app expo, which on app load should send API GET request to the backend to get order data, and based on that data I'm either displaying screen A(delivered) or B(order on it's way). I want to add this API call inside the SplashScreen when app still loads so when app is loaded there is no delay in getting API data and displaying screen A/B.
I have a simple useEffect function to call API like this:
const [data, setData] = useState{[]}
useEffect(() => {
const getData = async () => {
try {
const response = await axios.get(url);
if (response.status.code === 200 ) {
setData (response.data) // to save data in useState
}
} else if (response.status.code != 200) {
throw new Error();
}
} catch (error) {
console.log(error);
}
};
getData();
}, []);
and then in the return:
if (data.order.delivered) {
return <ScreenA />
}
else if (!data.order.delivered) {
return <ScreenB />
else {return <ScreenC />}
The issue is that sometimes if API is slow, then after splash screen app has a white screen, or ScreenC can be seen. How can I call API in the splashscreen while app is loading and have a nicer ux?
you can make a custom hook with simple UseState and put it after you've fetched your data
const [loading, setLoading] = useState(true)
...
useEffect(() => {
const getData = async () => {
try {
const response = await axios.get(url);
if (response.status.code === 200 ) {
setData (response.data)
// When data is ready you can trigger loading to false
setLoading(false)
}
...
and After that, you can use a Simple If statement on top of your app.js file
like this
if (!loaded) {
return <LoadingScreen/>; // whetever page you want to show here ;
}
you can use expo expo-splash-screen to achieve this goal:
call this hook on mount...
import * as SplashScreen from 'expo-splash-screen';
const [appIsReady, setAppIsReady] = useState(false);
useEffect(() => {
async function prepare() {
try {
// Keep the splash screen visible while we fetch resources
await SplashScreen.preventAutoHideAsync();
// Pre-load fonts, make any API calls you need to do here
await Font.loadAsync(Entypo.font);
// Artificially delay for two seconds to simulate a slow loading
// experience. Please remove this if you copy and paste the code!
await new Promise(resolve => setTimeout(resolve, 2000));
} catch (e) {
console.warn(e);
} finally {
// Tell the application to render
setAppIsReady(true);
}
}
prepare();
}, []);
you can also check expo doc
i want to detect the current orientation of device in expo react native, this is my code that doesn't work:
import {
Dimensions,
} from 'react-native';
import * as ScreenOrientation from 'expo-screen-orientation';**
const App = () => {
...
useEffect(() => {
const isPortrait = () => {
const dimension = Dimensions.get('screen');
return dimension.height >= dimension.width;
};
Dimensions.addEventListener('change', () => {
const orientation = isPortrait() ? 'portrait' : 'landscape';
console.log('Dimensions orientation', orientation);
});
ScreenOrientation.addOrientationChangeListener((e) => {
console.log('e ', e);
});
}, []);
how ever when i rotate the device there is no logs so it's not firing?
This works for me:
const [orientation, setOrientation] = useState(
ScreenOrientation.Orientation.PORTRAIT_UP
);
useEffect(() => {
// set initial orientation
ScreenOrientation.getOrientationAsync().then((info) => {
setOrientation(info.orientation);
});
// subscribe to future changes
const subscription = ScreenOrientation.addOrientationChangeListener((evt) => {
setOrientation(evt.orientationInfo.orientation);
});
// return a clean up function to unsubscribe from notifications
return () => {
ScreenOrientation.removeOrientationChangeListener(subscription);
};
}, []);
You should set your orientation field as default in your app.json / app.config.js. The app is locked to the specified orientation if this field is set to another value.
Related doc is here:
https://docs.expo.dev/versions/v46.0.0/config/app/#orientation
This is the line that doesn't do anything. Broken, bugged, POS? All of the above?
ScreenOrientation.addOrientationChangeListener((e) => {
console.log(e);
});
I had this same issue. The listener function was never firing.
Adding expo-sensors to my project seems to have fixed the callback for me. I think expo-screen-orientation might depend on expo-sensors
Steps for adding:
npx expo install expo-sensors
Rebuild your expo development client. (For me that command is eas build --profile simulator, but that will depend on your eas config)
After that, the listener callback function started firing.
Here's a code snippet of where I add the listener:
useEffect(() => {
ScreenOrientation.addOrientationChangeListener((e) => {
console.log(e)
})
}, [])
You're using the wrong package.
From the expo-screen-orientation docs:
Screen Orientation is defined as the orientation in which graphics are painted on the device. ... For physical device orientation, see the orientation section of Device Motion.
I tried to create a simple react native application, and show my position in map, with react-native-maps.
const [coordinate, setCoordinate] = useState()
const getCoordinate = () => {
navigator.geolocation.getCurrentPosition(data => {
setCoordinate({
latitude: data.coords.latitude,
longitude: data.coords.longitude,
});
});
}
useEffect(() => {
getCoordinate();
})
The code works fine, I got my position, marked with a Marker. My problem is why the getCoordinate function calls itself continuously, and running non-stop ?
You are not passing a second argument to the useEffect (which should be an array of dependencies) which is causing it to run on every render.
Since you only want it to run once (essentially on mount), you need to pass an empty array as the second argument to your useEffect:
useEffect(() => {
getCoordinate();
}, [])