Attach ref to Reanimated ScrollView to access .scrollTo - react-native

Using react-native-reanimated v1.
I have created a snack reproducing this issue - https://snack.expo.io/#noitidart/reanimated-scroll-view-ref
I have created a reanimatable component out of ScrollView like this:
import { ScrollView } from 'react-native-gesture-handler';
import Reanimated from 'react-native-reanimated';
const ReanimatedScrollView = Reanimated.createAnimatedComponent(ScrollView);
When I render it I want to get a ref to it so I can do ref.current.scrollTo(). However the ref is coming back without scrollTo on it. Here is my code:
const ref = useRef();
const scrollToFoo = () => {
if (ref.current) {
ref.current.scrollTo({ y: 100 });
}
}
return (
<ReanimatedScrollView ref={ref} />
)
If I do this with a regular ScrollView, ref.current properly has scrollTo on it.

You can use getNode() to get access to the component:
ref.current.getNode().scrollTo({ y: 100 });

Related

How to animate expo-linear-gradient with reanimated?

I am using react-native-reanimated and want to animate the colors of my expo-linear-gradient. Unfortunately, nothing changes. I also created a Expo Snack.
import * as React from 'react';
import { View, Button } from 'react-native';
import Animated, {
interpolateColor,
useAnimatedProps,
useSharedValue,
withTiming,
} from 'react-native-reanimated';
import { LinearGradient } from 'expo-linear-gradient';
const AnimatedLinearGradient = Animated.createAnimatedComponent(LinearGradient);
export default function App() {
const colorsValue = useSharedValue(1);
const animatedProps = useAnimatedProps(() => {
return {
colors: [
interpolateColor(colorsValue.value, [0, 1], ['#FFFFFF', '#000000']),
interpolateColor(colorsValue.value, [0, 1], ['#FFFFFF', '#00ff00']),
],
};
});
return (
<View>
<AnimatedLinearGradient
animatedProps={animatedProps}
style={{ height: 400, width: '100%' }}
/>
<Button
title="Change colors"
onPress={() => (colorsValue.value = withTiming(0, { duration: 2000 }))}
/>
</View>
);
}
Am I using animatedProps wrongly here? Any help would greatly be appreciated.
unfortunately, I'm not sure you can do that. You're using correctly the useAnimatedProps hook, but usually it doesn't work for all properties.
If you want to achieve this type of animation, I highly recommend you to try the LinearGradient component from #shopify/react-native-skia package.
You can easily reuse the same logic, but with the Skia values:
const colorsValue = useSharedValue(1);
const skiaFirstColor = useValue(0);
const skiaSecondColor = useValue(0);
useSharedValueEffect(() => {
skiaFirstColor.current = interpolateColor(colorsValue.value, [0, 1], ['#FFFFFF', '#000000']);
skiaSecondColor.current = interpolateColor(colorsValue.value, [0, 1], ['#FFFFFF', '#00ff00']);
}, colorsValue); // you can pass other shared values as extra parameters
const colors = useComputedValue(() => {
return [skiaFirstColor.current, skiaSecondColor.current]
}, [skiaFirstColor, skiaSecondColor])
return (<...
<Canvas>
<LinearGradient colors={colors} />
</Canvas>
</>)
Let me know if it helps.
I think it is not possible to do this with expo-linear-gradient because under the hood of this component on ios for example is CALayer and if you check reanimated docs for useAnimatedProps it says that:
Only "native" properties of "native views" can be set via useAnimatedProps. The most common usecase for this hook is when we want to animate properties of some third-party native component, since most of the properties for the core React Native components are a part of the styles anyways (at least the properties for which it makes sense to be animated). You can use the following functions to animate properties that Reanimated don't support by default:
addWhitelistedNativeProps() is used to animate properties that trigger layout recalculation, you can find them here.
addWhitelistedUIProps() is used for properties that are updated directly on the UI thread, currently allowed props are listed here.
Also looks like it is not possible to do with SVG - https://github.com/software-mansion/react-native-reanimated/issues/690
Maybe this example can help you to build your animation with SVG https://github.com/FullstackStation/react-native-svg-animated-linear-gradient

React Native Hook problem [ useNavigation ]

I am writing applications with React Native. I am using typescript. I am using Hook and getting an error in the application. When I searched, Hook is valid as of React-Native version 0.59.0 but I'm having trouble.
How can I solve it?
Hook Issue App
http://prnt.sc/vvkotk
import { useNavigation } from "#react-navigation/native";
import React from "react";
import { Dimensions, Image, StyleSheet } from "react-native";
import { Box, Header, Text } from "../../components";
import { useTheme } from "../../components/Theme";
const Drawer = () => {
const navigation = useNavigation();
const theme = useTheme();
return (
<Box flex={1}>
<Box flex={0.2} backgroundColor="white">
<Box
position="absolute"
top={0}
left={0}
right={0}
bottom={0}
borderBottomRightRadius="xl"
backgroundColor="secondary"
>
It looks like it doesn't recognise your custom useTheme hook. Please make sure the filename starts with use so useTheme.tsx of useTheme.jsx. Check the filename of your Drawer component as well to be sure. It should contain .jsx or .tsx.

use useState hook, however the setter function is undefined at runtime

I am using useState hook in my react-native project. I have a screen which renders my custom component named MyComponent. The setter function of state is called in MyComponent 's onSelected callback.
import React, {useState} from 'react';
import MyComponent from './components/MyComponent'
const MyScreen=()=> {
...
const {parts, setParts} = useState(initialParts);
return (<View>
<MyComponent onSelected={()=> {
...
setParts(newParts)
}}/>
</View>)
}
...
MyComponent looks like this, in the onPress callback of TouchableOpacity, it calls the passed in onSelected function:
const MyComponent= ({onSelected})=> {
...
return (<TouchableOpacity onPress={()=>{
onSelected();
...
}}>
...
</TouchableOpacity>)
}
When I run my app on iOS emulator, the screen shows, when I tap on MyComponent, I get error TypeError: setParts is not a function. (In setParts(newParts)), 'setParts' is undefined.
Why I get this error?
Your destructuring here seems wrong:
const {parts, setParts} = useState(initialParts);
Shouldn't be this:
const [parts, setParts] = useState(initialParts);
?
Hmmm, it seems like you have to read the React official documentation to know more about UseState.
here is fix to your code:
const MyScreen = () => {
const [parts, setParts] = useState(initialParts) // see this fix.
return (
<View>
<MyComponent
onSelected={() => {
setParts(newParts)
}}
/>
</View>
)
}
basically, it is in the form of array de-structuring instead of object like you wrote above.
learn more: https://reactjs.org/docs/hooks-state.html

Using a class as props in a react native component

I'm learning react (coming from a native iOS/Swift background) and I'm a bit confused about something I can't get to work.
I have a component that accepts props, so I figured I would write a class to model those props:
class HeaderProps {
text: string;
constructor(headerText:string) {
this.text = headerText;
}
}
// Make a component
const Header = (props:HeaderProps) => {
const { textStyle, viewStyle } = styles;
return (
<View style={viewStyle}>
<Text style={textStyle}>{props.text}</Text>
</View>
);
};
and I'm exporting from my component like so:
export {Header, HeaderProps};
I'm then importing it:
import {Header, HeaderProps} from './src/components/header';
// Create a component
const App = () => ( <Header headerText={ new HeaderProps('Album') } />);
No text is appearing in my component.
If I just pass a string through as props it works fine, can't think of any reason why sending a class through wouldn't work.
I'm using flow type to declare the types of my arguments, not sure if that might be causing any issues.
A point in the right direction would be much appreciated!

Text and TouchableOpacity Style Type Annotations

I am trying to type annotate my React Native project using Flow, but I am having trouble finding the type definitions for the Text and TouchableOpacity elements so I can reference their style prop type definitions. How can I import and/or reference the type definitions for these elements?
Code below:
// #flow
import * as React from "react";
import { Text, TouchableOpacity } from "react-native";
type Props = {
segmentIndex: number,
segmentInfo: {
title: string
},
segmentStyle: ???, // WHAT SHOULD I USE HERE?
titleStyle: ???, // WHAT SHOULD I USE HERE?
onSelection: (number) => void
}
export const SegmentButton = (props: Props) => {
const _segmentPressed = () => {
props.onSelection(props.segmentIndex)
}
return (
<TouchableOpacity style={props.segmentStyle} onPress={_segmentPressed}>
<Text style={props.titleStyle}>{props.segmentInfo.title.charAt(0).toUpperCase() + props.segmentInfo.title.substring(1)}</Text>
</TouchableOpacity>
)
}
There are many ways to define StyleSheet type.
1. react-native generic way
reference from react-native library,
SwipeableQuickActionButton.js
import { View } from 'react-native';
type Prop = {
style?: ?View.propTypes.style,
}
2. react-navigation generic way
reference from react-navigation library,
TypeDefinition.js
export type Style =
| { [key: string]: any }
| number
| false
| null
| void
| Array<Style>;
If you already installed react-navigation, import it from:
import type { Style } from 'react-navigation/src/TypeDefinition';
type Prop = {
style?: Style,
}
Or you can still use it by define in your own file.
3. make Style type specific for <Text /> and <TouchableOpacity />
It would be the hard way -- although doable, see if that worth the trouble.
take <Picker /> for reference, it defined itemStyle for <Text /> like below, which corresponding to text style for each picker item.
var StyleSheetPropType = require('StyleSheetPropType');
var TextStylePropTypes = require('TextStylePropTypes');
var TextStyle = StyleSheetPropType(TextStylePropTypes);
type Prop = {
itemStyle: TextStyle
}
To use it in your own library, import them from:
import TextStylePropTypes from 'react-native/Libraries/Text/TextStylePropTypes';
import StyleSheetPropType from 'react-native/Libraries/StyleSheet/StyleSheetPropType';
let TextStyle = StyleSheetPropType(TextStylePropTypes);
type Prop = {
style?: ?TextStyle,
}