how to transfer RecyclerListView from class component to functional - react-native

I faced RecyclerListView for the first time in legacy code, so I needed to rewrite that in functiona style, but when React tries to return RecyclerListView, programm freezes and do not even enter renderBetItem function, console.log doesn`t even appear. Here is the code parts
let dataProvider = new DataProvider((r1, r2) => {
return true;
});
let layoutProvider = new LayoutProvider(
() => 0,
(type, dim) => {
dim.width = width;
dim.height = 110;
}
);
componentDidMount() {
this.setState({isLoading: true});
this.props.footballEvents && this.initialManipulations(this.props.footballEvents);
this.setState({isLoading: false});
}
initialManipulations = (events) => {
if (events.length) {
const newEventArr = events.map((event) => eventManipulations(event, 'fromFootball'));
this.setState({liveEvents: this.dataProvider.cloneWithRows(newEventArr), loading: false});
}
}
const renderBetItem = (type, data) => {
console.log('entered renderBetItem')
return (
<View><Text>Hello</Text></View>
)
}
return (
<View style={{backgroundColor: whiteLabel.mainBackground, flex: 1}}>
{isLoading === false ?
<RecyclerListView
rowRenderer={renderBetItem}
key={keyForLive}
dataProvider={liveEvents}
layoutProvider={layoutProvider}
/>
:
<ActivityIndicator
color={whiteLabel.homeTabColorActive}
size='large'
style={{marginTop: '20%'}}
/>
}
</View>
)
Do you have any idea what`s wrong with this code?

Related

How to use asyncStorage inside useEffect

I'm building a mobile game using react native and I'm trying to retrieve the best value storage on it to display on the screen. The problem is that it seems that react native is rendering the screen before it retrieves the value and then it doesn't re-render when the value is updated using setBest(), so no value is displayed.
Here is the code:
const navigation = useNavigation()
const [result, setResult] = useState('')
const [best, setBest] = useState('')
useEffect(() => {
const Storage = async (key,value) => {
await AsyncStorage.setItem(key,value)
}
const Retrieve = async (key) => {
const value = await AsyncStorage.getItem(key)
setBest(()=>value)
}
Retrieve('1').catch(console.error)
setResult(route.params.paramKey)
if(route.params.paramKey>best){
var aux = result.toString()
Storage('1',aux)
console.log(best)
}
}, [])
return (
<View style={styles.container}>
<View style={styles.textView}>
<Text style={styles.tituloText}>Melhor pontuação</Text>
<Text style={styles.tituloText}>{best}</Text>
<Text style={styles.tituloText}>Sua pontuação</Text>
<Text style={styles.resultText}>{result}</Text>
<View style={styles.viewBtn}>
<TouchableOpacity style={styles.viewBack} onPress={() => navigation.navigate('Modo1')}>
<Icon style={styles.iconBack} name="backward" />
</TouchableOpacity>
<TouchableOpacity style={styles.viewHome} onPress={() => navigation.dispatch(StackActions.popToTop)}>
<Icon style={styles.iconBack} name="home" />
</TouchableOpacity>
</View>
</View>
</View>
);
}
Thanks for the help guys! I've been struggling with this for days and any help will be appreciated!
This is how you retrieve the value..
useEffect(() => {
AsyncStorage.getItem('key').then(value => {
if (value != null) {
console.log(value);
setBest(value);
}
});
}, []);
also don't forget to add the import statement..
To set the value you must use
AsyncStorage.setItem('key', value);
You can use Async Functions inside of ~useEffect()` like this:
useEffect(() => {
(async () => {
async function getData() {
try {
const value = await AsyncStorage.getItem('myKey');
if (value !== null) {
setData(value);
}
} catch (error) {
console.log(error);
}
}
getData();
})();
}, []);
}

Styling camera on React native

On a screen, I want to scan tickets this way :
class Tickets extends Component {
constructor(props) {
super(props);
this.state = {
Press: false,
hasCameraPermission: null,
reference: '',
lastScannedUrl:null,
displayArray: []
};
}
initListData = async () => {
let list = await getProductByRef(1);
if (list) {
this.setState({
displayArray: list,
reference: list.reference
});
}
console.log('reference dans initListData =', list.reference)
};
async UNSAFE_componentWillMount() {
this.initListData();
console.log('reference dans le state =', this.state.reference)
};
componentDidMount() {
this.getPermissionsAsync();
}
getPermissionsAsync = async () => {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({ hasCameraPermission: status === "granted" });
};
_onPress_Scan = () => {
this.setState({
Press: true
});
}
handleBarCodeScanned = ({ type, data }) => {
this.setState({ Press: false, scanned: true, reference: data });
this.props.navigation.navigate('ProductDetails', {reference : parseInt(this.state.state.reference)})
};
renderBarcodeReader = () => {
const { hasCameraPermission, scanned } = this.state;
if (hasCameraPermission === null) {
return <Text>{i18n.t("scan.request")}</Text>;
}
if (hasCameraPermission === false) {
return <Text>{i18n.t("scan.noaccess")}</Text>;
}
return (
<View
style={{
flex: 1,
...StyleSheet.absoluteFillObject
}}
>
<BarCodeScanner
onBarCodeScanned={scanned ? undefined : this.handleBarCodeScanned}
style={{ flex:1, ...StyleSheet.absoluteFillObject}}
/>
{scanned && (
<Button
title={"Tap to Scan Again"}
onPress={() => this.setState({ scanned: false })}
/>
)}
</View>
);
}
render() {
const { hasCameraPermission, scanned, Press } = this.state;
let marker = null;
console.log('displayArray', this.state.displayArray, 'reference', this.state.displayArray.reference)
return (
<View style={{flex:1}}>
<KeyboardAvoidingView behavior="padding" enabled style={{flex:1}}>
<ScrollView contentContainerStyle={{flexGrow: 1 }} >
{Press ? (
<View style={{flex:1}}>
{this.renderBarcodeReader()}
</View>
) : (
<View style={{flex:1, justifyContent:'center', alignItems:'center'}}>
<Button
color="#F78400"
title={i18n.t("scan.scan")}
onPress={this._onPress_Scan}>
</Button>
</View>
)}
</ScrollView>
</KeyboardAvoidingView>
</View>
);
}
}
export default Tickets;
This code gives me
As you can see I have a top and bottom margin. I would like there to be no space, for the camera to take the entire screen (and for any buttons to be displayed over the camera image)
How can I do it, the style of which element should I change?
Thanks for any help and explanations
can you leave your code for that part? now everything is okay but i believe the image width and height is static and you are not using resizeMode for that image, for camera it will be different .
you can check resizeMode for the camera library you are using

improving elements styles to make a full screen scan

I will need a helping hand to edit this page. i have all the elements but i need help styling.
I would like to have the camera (the image you see is the typical emulator camera, that's why it makes an image) in full screen and from above at the top, the message in red and the 'autocomplete.
If you want, to explain better, I would like to respect the image below: autocomplete at the top left above the camera in full screen.
would it be possible for you to help me, I'm getting a little confused. I tried to do a snack but failed. I will add it later if i can.
const autocompletes = [...Array(10).keys()];
const apiUrl = "https://5b927fd14c818e001456e967.mockapi.io/branches";
class Tickets extends Component {
constructor(props) {
super(props);
this.state = {
Press: false,
hasCameraPermission: null,
reference: '',
lastScannedUrl:null,
displayArray: []
};
}
initListData = async () => {
let list = await getProductByRef(1);
if (list) {
this.setState({
displayArray: list,
reference: list.reference
});
}
// console.log('reference dans initListData =', list.reference)
};
async UNSAFE_componentWillMount() {
this.initListData();
// console.log('reference dans le state =', this.state.reference)
};
componentDidMount() {
this.getPermissionsAsync();
}
getPermissionsAsync = async () => {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({ hasCameraPermission: status === "granted" });
};
_onPress_Scan = () => {
this.setState({
Press: true
});
}
handleBarCodeScanned = ({ type, data }) => {
this.setState({ Press: false, scanned: true, reference: data });
this.props.navigation.navigate('ProductDetails', {reference : parseInt(this.state.state.reference)})
};
renderBarcodeReader = () => {
const { hasCameraPermission, scanned } = this.state;
if (hasCameraPermission === null) {
return <Text>{i18n.t("scan.request")}</Text>;
}
if (hasCameraPermission === false) {
return <Text>{i18n.t("scan.noaccess")}</Text>;
}
return (
<View
style={{
flex: 1,
...StyleSheet.absoluteFillObject
}}
>
<BarCodeScanner
onBarCodeScanned={scanned ? undefined : this.handleBarCodeScanned}
style={{ flex:1, height:'100%', ...StyleSheet.absoluteFillObject}}
/>
{scanned && (
<Button
title={"Tap to Scan Again"}
onPress={() => this.setState({ scanned: false })}
/>
)}
</View>
);
}
handleSelectItem(item, index) {
const {onDropdownClose} = this.props;
onDropdownClose();
console.log(item);
}
render() {
const { hasCameraPermission, scanned, Press } = this.state;
let marker = null;
const {scrollToInput, onDropdownClose, onDropdownShow} = this.props;
// console.log('displayArray', this.state.displayArray, 'reference', this.state.displayArray.reference)
return (
<View style={styles.container}>
{Press ? (
<View style={{flex:1}}>
<View style={styles.dropdownContainerStyle}>
<Autocomplete
key={shortid.generate()}
containerStyle={styles.autocompleteContainer}
inputStyle={{ borderWidth: 1, borderColor: '#F78400'}}
placeholder={i18n.t("tickets.warning")}
pickerStyle={styles.autocompletePicker}
scrollStyle={styles.autocompleteScroll}
scrollToInput={ev => scrollToInput(ev)}
handleSelectItem={(item, id) => this.handleSelectItem(item, id)}
onDropdownClose={() => onDropdownClose()}
onDropdownShow={() => onDropdownShow()}
fetchDataUrl={apiUrl}
minimumCharactersCount={2}
highlightText
valueExtractor={item => item.name}
rightContent
rightTextExtractor={item => item.properties}
/>
</View>
{this.renderBarcodeReader()}
</View>
) : (
<View style={{flex:1, justifyContent:'center', alignItems:'center'}}>
<Button
color="#F78400"
title={i18n.t("scan.scan")}
onPress={this._onPress_Scan}>
</Button>
</View>
)}
</View>
);
}
}
export default Tickets;
This gives me (after pressing the button) :
SNACK CODE TEST
I notice You are using a component from Expo called BarCodeScanner
There's a github issue open about the fact that this component is not possible to be styled for full screen: https://github.com/expo/expo/issues/5212
However one user proposes a good solution: replace BarCodeScanner with Camera and use barcodescannersettings
Here's a link for the answer on the gitHub issue: https://github.com/expo/expo/issues/5212#issuecomment-653478266
Your code should look something like:
renderBarcodeReader = () => {
const { hasCameraPermission, scanned } = this.state;
[ ... ] // the rest of your code here
return (
<View
style={{
flex: 1,
...StyleSheet.absoluteFillObject
}}
>
<Camera
onBarCodeScanned={scanned ? undefined : this.handleBarCodeScanned}
style={{ flex:1}}
barCodeScannerSettings={{
barCodeTypes: [BarCodeScanner.Constants.BarCodeType.qr],
}}
/>
</View>
);
}

Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application

I want to login to my app but when I first login it works correctly but once I logout from my app and again try to login I get the following error 'Can't perform a state update on an unmount component'. Even though second time it also enters in the app but with the error which should be not there. Only one time it works correctly.
/*Component*/
const LoginScreen = props => {
let _isMounted = false;
const [isLoading , setIsLoading] = useState(false);
const [error , setError] = useState();
const [token , setToken] = useState();
const [url , setUrl] = useState({});
const dispatch = useDispatch();
/*Receiving the token*/
useEffect(() => {
let _isMounted = false;
const tokenReceive = () => {
if(Object.entries(url).length !== 0)
{
const getTokenFromUrl = url['url'].split('=')[1].split('&')[0];
if(getTokenFromUrl !== '')
{
setToken(getTokenFromUrl)
}
}
}
tokenReceive();
return(() => {
_isMounted = true
} )
}, [url ])
/*Dispatching after receiving token*/
useEffect(() =>{
_isMounted = true;
const loginHandler = async ()=> {
if(token !== undefined)
{
setError(null)
setIsLoading(true);
try{
await dispatch(authActions.login(token))
// if(_isMounted){
// props.navigation.navigate('afterAuth')
// }
}
catch(err)
{
setError(err.message)
}
setIsLoading(false)
if(_isMounted){
props.navigation.navigate('afterAuth')
}
}
}
loginHandler()
return(() => {
_isMounted = false
} )
} , [token ])
/*If any error occur*/
useEffect(() => {
if (error) {
Alert.alert('An error occured',error,[{text : 'Okay'}]);
}
return(() => {
console.log('Error'),
error
})
} , [error])
/*Event listener when url changes*/
useEffect(() => {
Expo.Linking.addEventListener('url', (url) => {
setUrl(url);
})
return () => {
Expo.Linking.removeEventListener('url' , (url) => {
setUrl(url)
})
};
} , [])
const prefix = Expo.Linking.makeUrl('token');
const _handlePressButtonAsync = async () => {
let result = await WebBrowser.openBrowserAsync(`https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=**********&response_type=id_token&redirect_uri=${prefix}&scope=openid email profile&response_mode=fragment&state=*****&nonce=****`);
};
return(
<ScrollView >
<TouchableWithoutFeedback onPress={() => {Keyboard.dismiss()}} >
<View style={styles.screen}>
<CircleDiv style={styles.userlogoDiv}>
<View style={styles.userLogo}>
<AntDesign name="user" size={RFValue(39)} color='#4D4848'/>
</View>
</CircleDiv>
<BackgroundUpper style={styles.upperDiv}>
<LogoLong style={ {marginTop : RFValue(100)}}/>
</BackgroundUpper>
<BackgroundLower >
<ScrollView style={{ flex : 1 } } decelerationRate='fast' >
<KeyboardAvoidingView behavior='position' keyboardVerticalOffset={Dimensions.get('screen').height / RFValue(10)}>
<View style={styles.loginDiv}>
<View style={styles.headingDiv}>
<Text style={styles.heading}>LOGIN</Text>
</View>
<View style={styles.buttonDiv}>
<TouchableOpacity>
{!isLoading ? <Button
style={styles.button}
title='LOGIN'
color= '#00B49D'
//onPress = {navigate}
onPress={_handlePressButtonAsync}
/> : <ActivityIndicator size="small" color={Colors.GREEN}/>}
</TouchableOpacity>
</View>
<View style={styles.forgetDiv}>
<Text style={styles.forget}>Forget Password</Text>
</View>
</View>
</KeyboardAvoidingView>
</ScrollView>
</BackgroundLower>
</View>
</TouchableWithoutFeedback>
</ScrollView>
)
};
Error - Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in %s.%s, a useEffect cleanup function,

fetch data from api row counter

By use of the following Code we can read Data from Server:
class SearchPage extends Component {
constructor(props) {
super(props);
var dataSource = new ListView.DataSource({rowHasChanged:(r1,r2) => r1.ruid != r2.guid});
this.state = {
id: 'SearchPage',
searchinpt: this.props.homesearchinpt,
shopid: this.props.shopid,
dataSource: dataSource.cloneWithRows(shopsArray),
isLoading: true
};
}
componentDidMount(){
this.fetchData();
}
fetchData() {
var name = this.state.searchinpt;
var API_URL = 'http://myurl';
var PARAMS = '?name=' + name;
var REQUEST_URL = API_URL + PARAMS;
fetch(REQUEST_URL)
.then((response) => response.json())
.then((responseData) => {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData),
loaded: true,
});
})
.done();
}
renderLoadingView() {
return (
<View style={styles.container}>
<Text>Loading</Text>
</View>
);
}
SearchisEmpty() {
return (
<View style={styles.container}>
<Text style={styles.notfound}>Not Found</Text>
</View>
);
}
SearchnotEmpty(){
return (
<ListView enableEmptySections = {true}
dataSource={this.state.dataSource}
renderRow=
{(shop) =>
<TouchableOpacity
onPress={(shop_id) => this.onSubmitPressed(shop.shop_id)} >
<View style={styles.container} >
<Image
source={{uri: shop.shop_logo}}
style={{width: 50, height: 50}}>
</Image>
<View>
<Text style={styles.shop_name}>{shop.shop_name}</Text>
<Text style={styles.shop_description}>{shop.shop_description}</Text>
</View>
</View>
<Text>{this.state.searchinpt}</Text>
<Text>{this.state.dataSource.getRowCount}</Text>
</TouchableOpacity>
}
style={styles.listView}
/>
);
}
onSubmitPressed(shopd){
this.props.navigator.push({
id: 'Shop',
passProps:{
thisshopid: shopd
}
})
}
render(shopsArray) {
if (!this.state.loaded) {
return this.renderLoadingView();
}else if(this.state.length < 1){
return this.SearchisEmpty();
} else{
return this.SearchnotEmpty();
}
}
}
There isn't any problem for Render.
Now we have some "if" that Whenever there isn't any Data, must show "Not found", But instead of (Not Found) it shows blank page
How can I solve the problem?
this.state.length will always be undefined as this.state is an object, not an array.
I would store the number of rows in the state to be able to control this behaviour. Something like this:
...
fetchData() {
...
fetch(REQUEST_URL)
.then((response) => response.json())
.then((responseData) => {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData),
loaded: true,
numRows: responseData.length
});
})
.done();
}
...
render(shopsArray) {
if (!this.state.loaded) {
return this.renderLoadingView();
}else if(this.state.numRows < 1){
return this.SearchisEmpty();
} else{
return this.SearchnotEmpty();
}
}