Testing error: useSharedValue is not a function while testing - react-native

Description
I'm using react-native-reanimated and when I'm testing, useSharedValue throws an error that it's not a function when using jest and react-native-testing-library. I've mocked react-native-reanimated by using the mock provided as part of the package. I also notice VS Code highlights that reanimated has no exported member useSharedValue, useAnimatedStyle and withTiming, however the component still runs properly without any errors.
Does anyone know what needs to be done to mock it properly?
Code
The Test to see if the component renders
import React from "react";
import { render } from "react-native-testing-library";
import { Switch } from "../src/native/Switch";
describe("Switch Package", () => {
it("renders", () => {
render();
});
});
Mock file which is placed in mocks named react-native-reanimated.js
jest.mock("react-native-reanimated", () => require("react-native-reanimated/mock") );
The Component using Reanimated - Switch.tsx
import { Button } from 'react-native';
import {
useSharedValue,
useAnimatedStyle,
withTiming,
Easing,
} from 'react-native-reanimated';
function Switch() {
const opacity = useSharedValue(0);
const style = useAnimatedStyle(() => {
return {
opacity: withTiming(opacity.value, {
duration: 200,
easing: sing.out(Easing.cubic),
}),
};
});
return (
<Animated.View style={[{width: 100, height: 100, backgroundColor: 'green'}, style]} />
<Button onPress={() => (opacity.value = 1)} title="Hey" />
);
}
Package Versions
React: 16.11.0
React Native: .062.2
React Native Reanimated: 2.0.0-alpha.3
ScreenShots
VS Code Screenshot
Test Error

Related

Warning: React has detected a change in the order of Hooks

I have run into this error in my code, and don't really know how to solve it, can anyone help me?
I get the following error message:
ERROR Warning: React has detected a change in the order of Hooks called by ScreenA. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks
import React, { useCallback, useEffect, useState } from "react";
import { View, Text, StyleSheet, Pressable } from "react-native";
import { useNavigation } from '#react-navigation/native';
import { DancingScript_400Regular } from "#expo-google-fonts/dancing-script";
import * as SplashScreen from 'expo-splash-screen';
import * as Font from 'expo-font';
export default function ScreenA({ route }) {
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({ DancingScript_400Regular });
// 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();
}, []);
const onLayoutRootView = useCallback(async () => {
if (appIsReady) {
// This tells the splash screen to hide immediately! If we call this after
// `setAppIsReady`, then we may see a blank screen while the app is
// loading its initial state and rendering its first pixels. So instead,
// we hide the splash screen once we know the root view has already
// performed layout.
await SplashScreen.hideAsync();
}
}, [appIsReady]);
if (!appIsReady) {
return null;
}
const navigation = useNavigation();
const onPressHandler = () => {
// navigation.navigate('Screen_B', { itemName: 'Item from Screen A', itemID: 12 });
}
return (
<View style={styles.body} onLayout={onLayoutRootView}>
<Text style={styles.text}>
Screen A
</Text>
<Pressable
onPress={onPressHandler}
style={({ pressed }) => ({ backgroundColor: pressed ? '#ddd' : '#0f0' })}
>
<Text style={styles.text}>
Go To Screen B
</Text>
</Pressable>
<Text style={styles.text}>{route.params?.Message}</Text>
</View>
)
}
const styles = StyleSheet.create({
body: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
text: {
fontSize: 40,
margin: 10,
fontFamily: 'DancingScript_400Regular'
}
})
I have read the rules of hooks: https://reactjs.org/docs/hooks-rules.html
The output is correct, but i want to fix this error before i add more additions to the app
You need to move useNavigation use before early returns.
Instead, always use Hooks at the top level of your React function, before any early returns.
The key is you need to call all the hooks in the exact same order on every component lifecycle update, which means you can't use hooks with conditional operators or loop statements such as:
if (customValue) useHook();
// or
for (let i = 0; i< customValue; i++) useHook();
// or
if (customValue) return;
useHook();
So moving const navigation = useNavigation(); before if (!appIsReady) {return null;}, should solve your problem:
export default function ScreenA({ route }) {
const [appIsReady, setAppIsReady] = useState(false);
const navigation = useNavigation();
// ...
}

undefined is not an object _react.PropTypes.array

I am using React Native (Expo CLI). Since i reinstalled npm i have this error when i try to run npm start I found some similar erros related to react-native-snap-carousel (i am using it).
TypeError: undefined is not an object (evaluating '_react.PropTypes.array')
at node_modules\expo\build\environment\react-native-logs.fx.js:27:4 in error
at node_modules\react-native\Libraries\Core\ExceptionsManager.js:95:4 in reportException
at node_modules\react-native\Libraries\Core\ExceptionsManager.js:141:19 in handleException
at node_modules\react-native\Libraries\Core\setUpErrorHandling.js:24:6 in handleError
at node_modules\#react-native\polyfills\error-guard.js:49:36 in ErrorUtils.reportFatalError
at node_modules\metro-runtime\src\polyfills\require.js:203:6 in guardedLoadModule
at http://192.168.1.6:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false&strict=false&minify=false:202384:3 in global code
So, inside it's main file is imported {PropTypes} from "react"; and changed to import PropTypes from "prop-types"; (previously installed). Also changed propTypes.items: PopTypes.array.isRequired to propTypes.items:PropTypes.array, same to slideStyle (because I started getting new errors related to items and slideStyle are required) but now i am receiving new errors like this.
All errors are related to react-native-snap-carousel
Here is my package.json
Here is how i use react-native-snap-carousel
import React, { useState, useEffect } from "react";
import {
View,
StyleSheet,
Image,
Dimensions,
TouchableWithoutFeedback,
} from "react-native";
import { getBannersApi } from "../../Api/HomeBanner";
import Carousel, { Pagination } from "react-native-snap-carousel";
import { size } from "lodash";
import { useNavigation } from "#react-navigation/native";
import { SERVER_RESOURCERS } from "../../Utils/Constans";
const width = Dimensions.get("window").width;
const height = 160;
export default function Banner() {
const [banners, setBanners] = useState(null);
const [banneActive, setBanneActive] = useState(0);
const navigation = useNavigation();
useEffect(() => {
(async () => {
const response = await getBannersApi();
setBanners(response.data);
})();
}, []);
const goToProduct = (id) => {
navigation.push("product", { idProduct: id });
};
if (!banners) return null;
const renderItem = ({ item }) => {
return (
<TouchableWithoutFeedback
onPress={() => goToProduct(item.attributes.product.data.id)}
>
<Image
style={styles.carousel}
source={{
uri: `${SERVER_RESOURCERS}${item.attributes.banner.data[0].attributes.formats.small.url}`,
}}
/>
</TouchableWithoutFeedback>
);
};
return (
<View style={styles.container}>
<Carousel
layout="default"
data={banners}
sliderWidth={width}
itemWidth={width}
renderItem={renderItem}
loop={true}
onSnapToItem={(i) => setBanneActive(i)}
autoplay={true}
autoplayInterval={5000}
autoplayDelay={2000}
/>
<Pagination
dotsLength={size(banners)}
activeDotIndex={banneActive}
inactiveDotOpacity={0.6}
inactiveDotScale={0.6}
containerStyle={styles.dotsContainer}
dotStyle={styles.dot}
dotColor={styles.dot.backgroundColor}
inactiveDotColor={styles.dot.backgroundColor}
/>
</View>
);
}
I noticed react-native-snap-carousel is not supported anymore so I migrated to react-native-reanimated-carousel

In React Native, creating a canva and calling getcontext create error

I am trying to use a function called readpixels from this github page and in this function one need to get the context of a canva, but since I am using React Native, I cannot use expressions like new Image() or document.createElement('canvas') so I am trying to do an equivalent using React Native functions.
Here is a minimal version of the code:
import React, { useState, useEffect, useRef } from 'react';
import { Button, Image, View } from 'react-native';
import * as ImagePicker from 'expo-image-picker';
import Canvas from 'react-native-canvas';
export function Canva() {
const ref = useRef(null);
useEffect(() => {
if (ref.current) {
const ctx = ref.current.getContext('2d');
if (ctx) {
Alert.alert('Canvas is ready');
}
}
}, [ref]);
return (
<Canvas ref={ref} />
);
}
function readpixels(url, limit = 0) {
const img = React.createElement(
"img",
{
src: url,
},
)
const canvas = Canva()
const ctx = canvas.getContext('2d')
return 1
}
export default function ImagePickerExample() {
const [image, setImage] = useState(null);
const pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
quality: 1,
});
readpixels(result.uri)
if (!result.cancelled) {
setImage({uri: result.uri, fileSize: result.fileSize});
}
};
return (
<View style={{ flex: 1, backgroundColor: "white", marginTop: 50 }} >
<Button title="Pick image from camera roll" onPress={pickImage} />
{image && <Image source={{ uri: image.uri }} style={{ width: 200, height: 200 }} />}
</View>
);
}
And here is the error that I get:
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
I have checked the three suggestions to solve the issue, but it did not work.
Thank you
p.s: in order to reproduce the code, you would need to install the react-native-canvas package

Flatlist undefined is not an object React-native

I am building a simple React-native app with Expo for rating Github repositories and ran into a nasty issue. When I am trying to render a list of the repositories with Flatlist it throws me the following error: undefined is not an object (evaluating 'repository.fullName'); although my code is pretty much identical to the one in React-native docs. Here is the RepositoryList.jsx where the Flatlist is being rendered:
import React from 'react';
import { FlatList, View, StyleSheet } from 'react-native';
import RepositoryItem from './RepositoryItem'
const styles = StyleSheet.create({
separator: {
height: 10,
},
});
const repositories = [
{
id: 'rails.rails',
fullName: 'rails/rails',
description: 'Ruby on Rails',
language: 'Ruby',
forksCount: 18349,
stargazersCount: 45377,
ratingAverage: 100,
reviewCount: 2,
ownerAvatarUrl: 'https://avatars1.githubusercontent.com/u/4223?v=4',
},
{
id: 'reduxjs.redux',
fullName: 'reduxjs/redux',
description: 'Predictable state container for JavaScript apps',
language: 'TypeScript',
forksCount: 13902,
stargazersCount: 52869,
ratingAverage: 0,
reviewCount: 0,
ownerAvatarUrl: 'https://avatars3.githubusercontent.com/u/13142323?v=4',
}
];
const ItemSeparator = () => <View style={styles.separator} />;
const RepositoryList = () => {
return (
<FlatList
data={repositories}
ItemSeparatorComponent={ItemSeparator}
renderItem={({repository}) => <RepositoryItem repository={repository}/> }
/>
);
};
export default RepositoryList
and RepositoryItem.jsx which should be rendered within the Flatlist:
import React from 'react'
import {View, Text, StyleSheet} from 'react-native'
const RepositoryItem = ({repository}) => {
return(
<View style={styles.item}>
<Text>Full name:{repository.fullName}</Text>
<Text>Description:{repository.description}</Text>
<Text>Language:{repository.language}</Text>
<Text>Stars:{repository.stargazersCount}</Text>
<Text>Forks:{repository.forksCount}</Text>
<Text>Reviews:{repository.reviewCount}</Text>
<Text>Rating:{repository.ratingAverage}</Text>
</View>
)
}
styles = StyleSheet.create({
item: {
marginHorizontal: 16,
backgroundColor: 'darkorange'
},
});
export default RepositoryItem
After doing my research I found that a lot of people have run into this issue too, and apparently it persists since 0.59 (my React-native is on 0.62, Windows). Apparently the error is being cause by a babel module '#babel/plugin-proposal-class-properties' and the solution would be deleting this module from .babelrc, according to this Github thread https://github.com/facebook/react-native/issues/24421. The problem is that my babel.config.js is extremely simple, and I don't see how I can exclude this module from being required for babel to work. My babel.config.js:
module.exports = function(api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
};
};
Perhaps there is a way to exclude it through tweaking babel in node_modules, but this solution seems unlikely. Any help or suggestions regarding this issue will be greatly appreciated!
I think your problem consists in destructuring repository in your renderItem method of the FlatList.
You cannot just destructure whatever you want, you have to destructure item from the Flatlist.
Try this way:
const RepositoryList = () => {
return (
<FlatList
data={repositories}
ItemSeparatorComponent={ItemSeparator}
renderItem={({ item }) => <RepositoryItem repository={item}/> }
/>
);
};
Or, if you really want to
const RepositoryList = () => {
return (
<FlatList
data={repositories}
ItemSeparatorComponent={ItemSeparator}
renderItem={({ item: repository }) => <RepositoryItem repository={repository}/> }
/>
);
};

can react-native-root-siblings work with react-redux

in a handleClick function, update the rootSiblings like this,
handleClick() { this.progressBar.update( <ProgressBar /> ); }
and in ProgressBar component,
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import { View } from 'react-native';
const getFinishedWidth = progress => ({ width: progress * totalWidth });
const getUnfinishedWidth = progress => ({ width: (1 - progress) * totalWidth });
function CustomerReassignProgressBar(props) {
const { progress } = props;
return (
<View style={styles.bar}>
<View style={getFinishedWidth(progress)} />
<View style={getUnfinishedWidth(progress)} />
</View> );
}
CustomerReassignProgressBar.propTypes = { progress: PropTypes.number, };
const mapStateToProps = state => ({ progress: state.batchReassignProgress, });
export default connect(mapStateToProps)(ProgressBar);
then, when calling handleClick(), the app crushed, the error is, 'Could not find "store" in either the context or props of "Connect(ProgressBar)". Either wrap the root component in a , or explicitly pass "store" as a prop to "Connect(ProgressBar)".'
if I don't use connect in component, it works well. So, I guess, maybe rootSiblings can not work with react-redux. But does anyone knows this problem?
Upgrade to react-native-root-siblings#4.x
Then
import { setSiblingWrapper } from 'react-native-root-siblings';
import { Provider } from 'react-redux';
const store = xxx;// get your redux store here
// call this before using any root-siblings related code
setSiblingWrapper(sibling => (
<Provider store={store}>{sibling}</Provider>
));