React is not defined with react-native-svg in React Native - react-native

I'm trying to use SVG in my project with react-native-svg and react-native-svg-transformer
, but I'm getting error React is not defined in the SVG file.
These are my configurations
metro.config.js
module.exports = (async () => {
const {
resolver: { sourceExts, assetExts }
} = await getDefaultConfig();
const config1 =
{transformer: {
babelTransformerPath: require.resolve("react-native-svg-transformer")
},
resolver: {
assetExts: assetExts.filter(ext => ext !== "svg"),
sourceExts: [...sourceExts, "svg"]
}}
const config2 ={
transformer: {
// eslint-disable-next-line #typescript-eslint/require-await
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: true
}
}),
babelTransformerPath: require.resolve('react-native-typescript-transformer')
}}
return mergeConfig(config1, config2)
})();
declarations.d.ts
declare module "*.svg" {
import React from 'react';
import { SvgProps } from "react-native-svg";
const content: React.FC<SvgProps>;
export default content;
}
I have tried the command yarn start --reset-cache but it didn't work

Related

Expo-AV Audio Error When Using CreateAsync URI. How can I fix?

I am receiving the following error message when loading a url mp3 file using expo-av in React Native.
Possible Unhandled Promise Rejection (id: 2):
Error: The AVPlayerItem instance has failed with the error code -1004 and domain "NSURLErrorDomain".```
Here is a simplified version of my code:
import { Text, View } from 'react-native';
import React, { useState, useEffect } from 'react';
import { Audio } from 'expo-av';
const AudioPlayer = ({ audioURL }) => {
const [playbackInstance, setPlaybackInstance] = useState();
const [playbackInstanceInfo, setPlaybackInstanceInfo] = useState({
position: 0,
duration: 0,
state: 'Buffering',
});
async function togglePlay() {
if (playbackInstanceInfo.state === 'Playing') {
setPlaybackInstanceInfo({
...playbackInstanceInfo,
state: 'Paused',
});
await playbackInstance.pauseAsync();
} else {
setPlaybackInstanceInfo({
...playbackInstanceInfo,
state: 'Play',
});
await playbackInstance.playAsync();
}
}
const onPlaybackStatusUpdate = status => {
if (status.isLoaded) {
setPlaybackInstanceInfo({
...playbackInstanceInfo,
position: status?.positionMillis,
duration: status?.durationMillis || 0,
state: status.didJustFinish
? 'Ended'
: status.isBuffering
? 'Buffering'
: status.shouldPlay
? 'Playing'
: 'Paused',
});
} else {
if (status.isLoaded === false && status.error) {
const errorMsg = `Encountered a fatal error
during playback: ${status.error}`;
console.log(errorMsg, 'error');
}
}
};
useEffect(() => {
const loadAudio = async () => {
const { sound } = await Audio.Sound.createAsync(
{ uri: audioURL },
{ shouldPlay: false },
onPlaybackStatusUpdate
);
setPlaybackInstance(sound);
};
loadAudio();
}, []);
useEffect(() => {
return playbackInstance
? () => {
playbackInstance.unloadAsync();
}
: undefined;
}, [playbackInstance]);
return (
<View></View>
)};
export default AudioPlayer;
Dependency Versions:
"expo": "^46.0.0",
"expo-av": "~12.0.4",
"react-native": "0.69.6"
I tried to delete node modules and package-lock.json, then reinstall, but that didn't help. I tried to update expo-av to 13.0.1 but I get a warning telling me that some dependencies I have are not compatible with it, so just went back to ~12.0.4. I'm using Node.js 15.0.1 with Express ^4.17.1

metro.config.js How to add svg and css transformer?

I'm bad in understanding what's happening in metro.config.js file
I already added svg transformer. Now I need to add css transformer.
I have such metro.config.js file:
const { getDefaultConfig } = require("metro-config");
module.exports = (async () => {
const {
resolver: { sourceExts, assetExts }
} = await getDefaultConfig();
return {
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false
}
}),
babelTransformerPath: require.resolve("react-native-svg-transformer")
},
resolver: {
assetExts: assetExts.filter(ext => ext !== "svg"),
sourceExts: [...sourceExts, "svg"]
}
};
})();
In order to have react-native-css-modules I need to place such content in metro.config.js:
const { getDefaultConfig } = require("metro-config");
module.exports = (async () => {
const {
resolver: { sourceExts },
} = await getDefaultConfig();
return {
transformer: {
babelTransformerPath: require.resolve("react-native-css-transformer"),
},
resolver: {
sourceExts: [...sourceExts, "css"],
},
};
})();
But if I just replace the content svg transformer will not work.
How can I combine two metro.config.js files?

'react-native-fbads' throws error saying this package itself specifies a `main` module field that could not be resolved

I have integrated react-native-fbads in my React Native application. Now when i run the application, it runs and then shows this following error:
Error: While trying to resolve module `react-native-fbads` from file `/Users/tanmoysarker/musiczi-mobile/app/Ads/Fb Ads/BannerAds/index.js`, the package `/Users/tanmoysarker/musiczi-mobile/node_modules/react-native-fbads/package.json` was successfully found. However, this package itself specifies a `main` module field that could not be resolved (`/Users/tanmoysarker/musiczi-mobile/node_modules/react-native-fbads/dist/lib/index.js`. Indeed, none of these files exist:
I have no idea why this is happening. Here's my metro.config file :
const { getDefaultConfig } = require('metro-config')
module.exports = (async () => {
const {
resolver: { sourceExts, assetExts }
} = await getDefaultConfig()
return {
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false
}
}),
babelTransformerPath: require.resolve('react-native-svg-transformer')
},
resolver: {
assetExts: assetExts.filter((ext) => ext !== 'svg'),
sourceExts: [...sourceExts,'jsx','js', 'ts', 'tsx', 'svg' ]
}
}
})()

Metro config not accepting blockList

I am building a react-native app with expo, I am using the modules of react-native-svg-transformer and also amplify (where I have created functions). The problem is that the functions in the amplify directory have package.json files and do not work. This is why I'm trying to put the amplify directory in the blocList of the metro configuration, but I keep getting the error:
Failed to construct transformer: TypeError: Transformer is not a constructor
This is my metro config:
const { getDefaultConfig } = require("expo/metro-config")
// extra config is needed to enable `react-native-svg-transformer`
module.exports = (async () => {
const {
resolver: { sourceExts, assetExts },
} = await getDefaultConfig(__dirname)
return {
transformer: {
babelTransformerPath: require.resolve("react-native-svg-transformer"),
assetPlugins: ["expo-asset/tools/hashAssetFiles"],
},
resolver: {
assetExts: assetExts.filter((ext) => ext !== "svg"),
sourceExts: [...sourceExts, "svg"],
blockList: [/amplify.*/]
},
}
})()
I also tried this but it didn't work either:
const { getDefaultConfig } = require("expo/metro-config")
// extra config is needed to enable `react-native-svg-transformer`
module.exports = (async () => {
const {
resolver: { sourceExts, assetExts },
} = await getDefaultConfig(__dirname)
return {
transformer: {
babelTransformerPath: require.resolve("react-native-svg-transformer"),
experimentalImportSupport: false,
inlineRequires: true,
},
resolver: {
assetExts: assetExts.filter((ext) => ext !== "svg"),
sourceExts: [...sourceExts, "svg"],
blockList: [/amplify.*/]
},
}
})()
It was that some packages used metro-config#0.59 and I npm-installed metro-config#0.61 so they were incompatible.

how to mock async PermissionsAndroid.request in jest?

I have this code in react native i want to make a test:
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
{
title: 'Device current location permission',
message: 'Allow app to get your current location',
buttonNeutral: 'Ask Me Later',
buttonNegative: 'Cancel',
buttonPositive: 'OK',
}
);
i am looking at an answer here but seem not working: How to mock PermissionAndroid from react native
jest.doMock('react-native/Libraries/PermissionsAndroid/PermissionsAndroid', () => ({
...jest.requireActual('react-native/Libraries/PermissionsAndroid/PermissionsAndroid'),
request: () => ({
[PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION]: PermissionsAndroid.RESULTS.GRANTED,
}),
check: () => true,
}));
on ios i am doing it like this which was quick:
jest.spyOn(Geolocation, 'requestAuthorization').mockResolvedValue('granted');
i can't seem to think of a way how to do it in android?
I could recommend you to try with react-native-permissions. It already have a mock file that you can use. You can use Jest + React Testing Library Native.
In my case I used a jest-setup.js file
import {jest} from '#jest/globals';
jest.mock('react-native-permissions', () =>
require('react-native-permissions/mock'),
);
Then configure jest inside you package.json file
"jest": {
"preset": "react-native",
"setupFilesAfterEnv": [
"#testing-library/jest-native/extend-expect"
],
"transformIgnorePatterns": [
"node_modules/(?!(jest-)?react-native-permissions|)"
],
"setupFiles": [
"./jest-setup.js"
]
}
For Geolocation service I created a react-native-geolocation-service inside __mocks__/react-native-geolocation-service.js
export default {
getCurrentPosition: jest.fn().mockImplementation(successCallback => {
const position = {
coords: {
latitude: 57.7,
longitude: 11.93,
},
};
successCallback(position);
}),
};
In your App component you could have this
import React, {useEffect, useState} from 'react';
import { View } from 'react-native';
import {check, request, PERMISSIONS, RESULTS} from 'react-native-permissions';
import Geolocation from 'react-native-geolocation-service';
const App = () => {
const [location, setLocation] = useState(null);
const handleLocationPermission = async () => {
let permissionCheck = '';
if (Platform.OS === 'ios') {
permissionCheck = await check(PERMISSIONS.IOS.LOCATION_WHEN_IN_USE);
if (permissionCheck === RESULTS.DENIED) {
const permissionRequest = await request(
PERMISSIONS.IOS.LOCATION_WHEN_IN_USE,
);
permissionRequest === RESULTS.GRANTED
? console.warn('Location permission granted.')
: console.warn('Location perrmission denied.');
}
}
if (Platform.OS === 'android') {
permissionCheck = await check(PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION);
if (permissionCheck === RESULTS.DENIED) {
const permissionRequest = await request(
PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION,
);
permissionRequest === RESULTS.GRANTED
? console.warn('Location permission granted.')
: console.warn('Location perrmission denied.');
}
}
};
useEffect(() => {
handleLocationPermission();
}, []);
useEffect(() => {
Geolocation.getCurrentPosition(
position => {
const {latitude, longitude} = position.coords;
setLocation({latitude, longitude});
},
error => {
console.log(error.code, error.message);
},
{enableHighAccuracy: true, timeout: 15000, maximumAge: 10000},
);
}, []);
return (<View></View>)
}
Then in you test file you can test the behaviour using React Testing Library Native.
import React from 'react';
import {render, waitFor} from '#testing-library/react-native';
import App from '../App';
import {check} from 'react-native-permissions';
import Geolocation from 'react-native-geolocation-service';
describe('<UserScreen />', () => {
test('should check for permissions', async () => {
render(<App />);
await waitFor(() => {
expect(check).toHaveBeenCalledTimes(1);
expect(Geolocation.getCurrentPosition).toHaveBeenCalledTimes(1);
});
});
});
I wrote a similar and more detailed Post on my website.