this.refs x useRef (Is there any similarity?) - reactjs

I'm trying to use a library that uses this.ref, but I have to pass it to hooks. I'm not getting it.
Original code:
import ViewShot from "react-native-view-shot";
class ExampleCaptureOnMountManually extends Component {
componentDidMount () {
this.refs.viewShot.capture().then(uri => {
console.log("do something with ", uri);
});
}
render() {
return (
<ViewShot ref="viewShot" options={{ format: "jpg", quality: 0.9 }}>
<Text>...Something to rasterize...</Text>
</ViewShot>
);
}
}
My hook code:
export default function screenshot() {
const refs = useRef();
refs.viewShot.capture().then(uri => {
console.log('do something with ', uri);
});
return (
<View style={styles.container}>
<View style={styles.header} />
<ViewShot ref="viewShot" options={{format: 'jpg', quality: 0.9}}>
<View>
<Text>Hello World</Text>
</View>
</ViewShot>
<View style={styles.footer}>
<Button title="print" onPress={onCapture} />
</View>
</View>
);
}
Link Lib:
https://github.com/gre/react-native-view-shot

With useRef(), you don't do const refs = useRef();, you declare the ref:
const viewShot = useRef();
And then pass it in the ref attribute:
<ViewShot ref={viewShot} ...
You should now use it as viewShot.current.
Nevertheless, since your original code executed in componentDidMount, now you should also employ useEffect (notice the addition of .current):
useEffect(() => {
viewShot.current.capture().then(uri => {
console.log('do something with ', uri);
});
}, [])
Therefore:
export default function screenshot() {
const viewShot = useRef();
useEffect(() => {
viewShot.current.capture().then(uri => {
console.log('do something with ', uri);
});
}, [])
return (
<View style={styles.container}>
<View style={styles.header} />
<ViewShot ref={viewShot} options={{format: 'jpg', quality: 0.9}}>
<View>
<Text>Hello World</Text>
</View>
</ViewShot>
<View style={styles.footer}>
<Button title="print" onPress={onCapture} />
</View>
</View>
);
}

Related

react-native-reanimated, pass component as prop with animated close

I have a component which uses react-native-reanimated, how can I add hideSheet() to the component I am passing as a prop?
import Animated, { Easing } from "react-native-reanimated";
...
const BottomSheet = ({
children,
...
renderHeader,...
}) => {
const style = useMemo(
() => getStyleObj({ backgroundColor, secondSnapshot }),
[backgroundColor, secondSnapshot]
);
const [alignment] = useState(new Animated.Value(0));
const [alignmentChildren] = useState(new Animated.Value(0));
const [open, setOpen] = useState(true);
const WrapperComponent = tapToOpenEnabled ? Pressable : View;
const openSheet = () => {
Animated.timing(alignment, {
toValue: 1,
duration: 400,
easing: Easing.bezier(0.25, 0.1, 0.25, 1),
}).start();
};
const hideSheet = () => {
Animated.timing(alignment, {
toValue: 0,
duration: 400,
easing: Easing.bezier(0.25, 0.1, 0.25, 1),
}).start();
};
const toggleOpen = () => {
if (open) {
hideSheet();
setOpen(false);
} else {
openSheet();
setOpen(true);
}
};
I am passing the header component as a prop:
const renderSheetHeader = useCallback(() => {
return (
<View style={styles.headerCont}>
<Text style={styles.headerTXT}>Setup your reminders</Text>
<Icon name="closecircle" size={20} color={colors.GREYONE} *add hideSheet here* />
</View>
);
}, []);
return (
<BottomSheet
...
renderHeader={renderSheetHeader()}
...
>
return (
<WrapperComponent>
...
{renderHeader}
You could pass it as a parameter to your function.
const renderSheetHeader = useCallback((onHide) => {
return (
<View style={styles.headerCont}>
<Text style={styles.headerTXT}>Setup your reminders</Text>
<View style={styles.headerCont}>
<Text style={styles.headerTXT}>Setup your reminders</Text>
<Pressable onPress={() => onHide()}>
<Icon name="closecircle" size={20} color={colors.GREYONE} />
</Pressable>
</View>
</View>
);
}, []);
Then, call it as usual.
<WrapperComponent>
...
{(onHide) => renderHeader(onHide)}
In your WrapperComponent:
renderHeader(hideSheet)
However, if it is not necessary that you define this as a function (and I do not see a reason in your current code), then you should be better of to just create a normale JSX component.
export function SheetHeader(props) {
return (
<View style={styles.headerCont}>
<Text style={styles.headerTXT}>Setup your reminders</Text>
<View style={styles.headerCont}>
<Text style={styles.headerTXT}>Setup your reminders</Text>
<Pressable onPress={() => onHide()}>
<Icon name="closecircle" size={20} color={colors.GREYONE} />
</Pressable>
</View>
</View>
);
}
and call it in your WrapperComponent directly.
<SheetHeader onHide={hideSheet} />

How can I pass a variable to the previous screen by using React Navigation?

I'm using React Native. I tried to write this code:
//Screen A
//ignored the "import"
export function Hoge(Props) {
let onSelect = false
return(
<View>
<View>
<Text>{onSelect ? 'Selected' : 'Not Selected' }</Text>
</View>
<TouchableOpacity
onPress={() => {
navigation.navigate('ScreenB', { onSelect: onSelect });
}};>
<View><Text>Screen B</Text></View>
</TouchableOpacity>
</View>
)
}
//ScreenB
export function HogeHoge(Props) {
const [hoge, setHoge ] = useState(route.params.onSelect)
function goBack() {
setHoge(true)
navigation.goBack();
}
let screen = navigation.setOptions({
headerLeft: () => (
<TouchableOpacity onPress={() => {
goBack();
}}>
<Image
source={require('../../images/back_btn.png')}
style={commonStyles.back_btn}
/>
</TouchableOpacity>
),
})
return (
<View>{screen}</View>
)
};
referring to the following: https://github.com/react-navigation/react-navigation/issues/288
I hoped the "onSelect" is true, but it was false. How can I fix it?

Invalid use of hooks when calling component with onPress

I'm trying to work with modals when I click on a button from the header.
Say I have this component List, and List is using custom navigation options:
import { CustomModal } from './components/Modal';
const List = (props) => {
const [enteredUrl, setEnteredUrl] = useState('');
const urlInputHandler = (enteredUrl) => {
setEnteredUrl(enteredUrl);
};
const addUrlHander = () => {
console.log(enteredUrl);
}
return (
<View></View>
);
};
List.navigationOptions = (navData) => {
return {
headerTitle: 'Workouts',
headerRight: (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title='Add'
iconName='md-add'
onPress={() => {
CustomModal(); //here is the modal
}}
/>
</HeaderButtons>
),
headerBackTitle: null
};
};
My Modal component has this:
export const CustomModal = (props) => {
const [modalVisible, setModalVisible] = useState(false);
console.log(props);
return (
<Modal
animationType='slide'
transparent={false}
visible={modalVisible}
onRequestClose={() => {
Alert.alert('Modal has been closed.');
}}
>
<View style={{ marginTop: 22 }}>
<View>
<Text>Hello World!</Text>
<TouchableHighlight
onPress={() => {
setModalVisible(!modalVisible);
}}
>
<Text>Hide Modal</Text>
</TouchableHighlight>
</View>
</View>
</Modal>
);
}
But it is giving me the invalid hook error. Why is it that my onPress in my navigationOptions giving me this? Am I doing this wrong?
onPress is a callback, you can't put components in it. Probably what you want is something like this:
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<CustomModal/>
</HeaderButtons>
and the modal looks like
export const CustomModal = (props) => {
const [modalVisible, setModalVisible] = useState(false);
console.log(props);
return modalVisible?(
<Modal
animationType='slide'
transparent={false}
visible={modalVisible}
onRequestClose={() => {
Alert.alert('Modal has been closed.');
}}
>
<View style={{ marginTop: 22 }}>
<View>
<Text>Hello World!</Text>
<TouchableHighlight
onPress={() => {
setModalVisible(!modalVisible);
}}
>
<Text>Hide Modal</Text>
</TouchableHighlight>
</View>
</View>
</Modal>
):(
<Item
title='Add'
iconName='md-add'
onPress={() => setModalVisible(!modalVisible)}
/>
);
}

Show View when scroll up Scrollview

How to limit the quantity of View inside of a scrollview.
My component take too much time to render, because the map function renders too many views. I need to show only 10 views, and when scroll up, renders more 10.
I'm using react native, hooks and typescript.
First of all, if you have a large number of list data don't use scrollview. Because initially, it loads all the data to scrollview component & it costs performance as well.
Use flatlist in react-native instead of scrollview & you can limit the number of items to render in the initially using initialNumToRender. When you reach the end of the scroll position you can call onEndReached method to load more data.
A sample will like this
import React, { Component } from "react";
import { View, Text, FlatList, ActivityIndicator } from "react-native";
import { List, ListItem, SearchBar } from "react-native-elements";
class FlatListDemo extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
data: [],
page: 1,
seed: 1,
error: null,
refreshing: false
};
}
componentDidMount() {
this.makeRemoteRequest();
}
makeRemoteRequest = () => {
const { page, seed } = this.state;
const url = `https://randomuser.me/api/?seed=${seed}&page=${page}&results=20`;
this.setState({ loading: true });
fetch(url)
.then(res => res.json())
.then(res => {
this.setState({
data: page === 1 ? res.results : [...this.state.data, ...res.results],
error: res.error || null,
loading: false,
refreshing: false
});
})
.catch(error => {
this.setState({ error, loading: false });
});
};
handleRefresh = () => {
this.setState(
{
page: 1,
seed: this.state.seed + 1,
refreshing: true
},
() => {
this.makeRemoteRequest();
}
);
};
handleLoadMore = () => {
this.setState(
{
page: this.state.page + 1
},
() => {
this.makeRemoteRequest();
}
);
};
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: "86%",
backgroundColor: "#CED0CE",
marginLeft: "14%"
}}
/>
);
};
renderHeader = () => {
return <SearchBar placeholder="Type Here..." lightTheme round />;
};
renderFooter = () => {
if (!this.state.loading) return null;
return (
<View
style={{
paddingVertical: 20,
borderTopWidth: 1,
borderColor: "#CED0CE"
}}
>
<ActivityIndicator animating size="large" />
</View>
);
};
render() {
return (
<List containerStyle={{ borderTopWidth: 0, borderBottomWidth: 0 }}>
<FlatList
data={this.state.data}
renderItem={({ item }) => (
<ListItem
roundAvatar
title={`${item.name.first} ${item.name.last}`}
subtitle={item.email}
avatar={{ uri: item.picture.thumbnail }}
containerStyle={{ borderBottomWidth: 0 }}
/>
)}
keyExtractor={item => item.email}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader}
ListFooterComponent={this.renderFooter}
onRefresh={this.handleRefresh}
refreshing={this.state.refreshing}
onEndReached={this.handleLoadMore}
onEndReachedThreshold={50}
/>
</List>
);
}
}
export default FlatListDemo;
Check this for more informations.
I changed to Flatlist! But initialNumToRender is not working as expected.
The flatlist is rendering all 150 transactions, not only 15, and i have no idea what to do.
I'm running .map() from another array with all others transactions to create newMonths with only those transactions that i want to use data={newMonths}.
let newMonths = [];
const createArrayMonth = histInfos.map(function (info) {
if (info.created_at.slice(5, 7) === month) {
newMonths = [info].concat(newMonths);
}
});
them, i created my component:
function Item({ value }: { value: any }) {
let createdDay = value.item.created_at.slice(8, 10);
let createdMonth = value.item.created_at.slice(5, 7);
let createdYear = value.item.created_at.slice(2, 4);
function dateSelected() {
if (
month === createdMonth &&
year === createdYear &&
(day === '00' || day == createdDay)
) {
console.log('foi dateSelected');
const [on, setOn] = useState(false);
const Details = (on: any) => {
if (on === true) {
return (
<View style={styles.infos}>
<Text style={styles.TextInfos}>
{' '}
CPF/CNPJ: {value.item.cpf_cnpj}{' '}
</Text>
<Text style={styles.TextInfos}>
{' '}
Criado em: {value.item.created_at}{' '}
</Text>
<Text style={styles.TextInfos}>
{' '}
Endereço da carteira: {value.item.address}{' '}
</Text>
<Text style={styles.TextInfos}> Valor: {value.item.amount}BTC </Text>
</View>
);
} else {
return <View />;
}
};
return (
<View>
<TouchableOpacity
style={styles.card}
onPress={() => setOn(oldState => !oldState)}>
<View style={styles.dateStyleView}>
<Text style={styles.dateStyle}>{createdDay}</Text>
</View>
<View style={styles.left}>
<Text style={styles.title}>Venda rápida</Text>
<Text style={styles.semiTitle}>
{
{
0: 'Pendente',
1: 'Aguardando conclusão',
2: 'Cancelado',
100: 'Completo',
}[value.item.status]
}
</Text>
</View>
<View style={styles.right2}>
<Text style={styles.price}>R$ {value.item.requested_value}</Text>
</View>
</TouchableOpacity>
<View>{Details(on)}</View>
</View>
);
}
}
return dateSelected();}
and i call it here
return (
<ScrollView>
...
<View style={styles.center}>
...
<View style={styles.middle2}>
...
<FlatList
extraData={[refresh, newMonths]}
data={newMonths}
renderItem={(item: any) => <Item value={item} />}
keyExtractor={(item, index) => index.toString()}
initialNumToRender={15}
/>
</View>
</View>
</ScrollView>);}
The scroll bar in the right, start to increase until renders all transactions from the data:
App scroll bar

React Native FlatList only responds to touches sometimes

I have used FlatList in multiple places in my app previously without any issues, but now when I created a new one it doesn't seem to register touches/swipes correctly. Only like 1/6 touches seem to register.
See the video here: https://photos.app.goo.gl/NZCtVYX6GLVCQN392
This is how I use the FlatList:
render() {
return (
<Container>
...
<FlatList
data={this.state.exercises}
renderItem={({item}) =>
<SetsRepsAndWeightItem exercise={item}/>
}
keyExtractor={item => item.name}
style={style.list}
/>
</Container>
);
}
And the SetsRepsAndWeightItem:
render() {
return (
<View style={style.container}>
<View style={style.header}>
<Text style={style.headerText}>{this.props.exercise.name}</Text>
</View>
<View style={style.about}>
<TouchableWithoutFeedback onPress={this.handleSetsPressed}>
<StatisticNumber metric="Sets" value={7}/>
</TouchableWithoutFeedback>
<TouchableWithoutFeedback onPress={this.handleRepsPressed}>
<StatisticNumber metric="Reps" value={5}/>
</TouchableWithoutFeedback>
<TouchableWithoutFeedback onPress={this.handleWeightPressed}>
<StatisticNumber metric="kg" value={35}/>
</TouchableWithoutFeedback>
</View>
</View>
);
}
handleSetsPressed = () => {
console.log("sets pressed");
}
handleRepsPressed = () => {
console.log("reps pressed");
}
handleWeightPressed = () => {
console.log("weight pressed");
}
Also: the TouchableWithoutFeedback elements are not calling their onPress functions when they are touched.
The Container is as simple as this:
export default class Container extends Component {
static propTypes = {
children: Proptypes.any,
backgroundColor: Proptypes.string
};
render() {
const containerStyles = StyleSheet.flatten([
style.container,
this.props.backgroundColor ? { backgroundColor: this.props.backgroundColor } : null,
]);
return (
<TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
<View style={containerStyles}>
{this.props.children}
</View>
</TouchableWithoutFeedback>
);
}
}
The following two fixes solved the issues for me:
Remove the onPress={() => Keyboard.dismiss()} from the Container component
Move the TouchableWithoutFeedback into the StatisticNumber component, and pass onPress as a prop from SetsRepsAndWeightItem

Resources