Using react-spring for react-native - react-native

I want to use this library for react-native but couldn't figure out how. The documentation link for react-native is broken. Can i use the library for react-native?

React-Spring can be used for react-native. They have updated it for all platform.
Try this out:-
yarn add react-spring#5.3.0-beta.0
import React from 'react'
import { StyleSheet, Text, View, TouchableWithoutFeedback } from 'react-native'
import { Spring, animated } from 'react-spring/dist/react-spring-native.esm'
const styles = {
flex: 1,
margin: 0,
borderRadius: 35,
backgroundColor: 'red',
alignItems: 'center',
justifyContent: 'center',
}
export default class App extends React.Component {
state = { flag: true }
toggle = () => this.setState(state => ({ flag: !state.flag }))
render() {
const { flag } = this.state
return (
<Spring native from={{ margin: 0 }} to={{ margin: flag ? 100 : 0 }}>
{props => (
<TouchableWithoutFeedback onPressIn={this.toggle}>
<animated.View style={{ ...styles, ...props }}>
<Text>It's working!</Text>
</animated.View>
</TouchableWithoutFeedback>
)}
</Spring>
)
}
}
`

For anyone with issues, try using a different import. This worked for me on expo's react native.
import React, { Component } from 'react';
import { Text, View, TouchableWithoutFeedback } from 'react-native';
import { Spring, animated } from 'react-spring/renderprops-native';
const AnimatedView = animated(View);
const styles = {
flex: 1,
margin: 0,
backgroundColor: 'red',
alignItems: 'center',
justifyContent: 'center',
}
export default class App extends Component {
state = { flag: true }
toggle = () => this.setState(state => ({ flag: !state.flag }))
render() {
const { flag } = this.state
return (
<Spring
native
from={{ margin: 0 }}
to={{ margin: flag ? 100 : 0 }}
>
{props => (
<TouchableWithoutFeedback onPressIn={() => this.toggle()}>
<AnimatedView style={{ ...styles, ...props }}>
<Text>{flag ? "true" : 'false'}</Text>
</AnimatedView>
</TouchableWithoutFeedback>
)}
</Spring>
);
}
}

The example below works.
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View, TouchableWithoutFeedback} from 'react-native';
import { Spring, animated } from 'react-spring'
const AnimatedView = animated(View)
const styles = {
flex: 1,
margin: 0,
borderRadius: 35,
backgroundColor: 'red',
alignItems: 'center',
justifyContent: 'center',
}
type Props = {};
export default class App extends Component<Props> {
state = { flag: true }
toggle = () => this.setState(state => ({ flag: !state.flag }))
render() {
const { flag } = this.state
return (
<Spring native from={{ margin: 0 }} to={{ margin: flag ? 100 : 0 }}>
{props => (
<TouchableWithoutFeedback onPressIn={this.toggle}>
<AnimatedView style={{ ...styles, ...props }}>
<Text>It's working!</Text>
</AnimatedView>
</TouchableWithoutFeedback>
)}
</Spring>
);
}
}

Related

Why is React Native FlatList not working on Android but it is for Web?

I am using Expo to build a react native app with AWS for the backend.
I am trying to display a list of friends using FlatList and the AWS data. The list works and is visible on my web browser, but for some reason, it is not displaying on my Android phone. What might the issue be?
FriendsList.tsx
import { API, graphqlOperation } from 'aws-amplify';
import * as React from 'react';
import {useEffect, useState} from 'react';
import { FlatList, View, ScrollView, Text, StyleSheet } from 'react-native';
import { listUsers } from '../graphql/queries';
import FriendsListItem from '../components/FriendsListItem';
export default function FriendsList() {
const [ users, setUsers ] = useState([]);
useEffect( () => {
const fetchUsers = async () => {
try {
const usersData = await API.graphql(
graphqlOperation(
listUsers
)
)
setUsers(usersData.data.listUsers.items);
} catch (e) {
}
}
fetchUsers();
},[])
return (
<View style={ styles.container }>
<FlatList
style={{ width: '100%' }}
data={users}
renderItem={({ item }) => <FriendsListItem user={item} />}
keyExtractor={(item) => item.id}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
FriendsListItem.tsx
import * as React from 'react';
import { View, Text, StyleSheet, Image, TouchableWithoutFeedback } from 'react-native';
import { API, graphqlOperation, Auth } from "aws-amplify";
import { User } from './types';
export type FriendsListItemProps = {
user: User;
}
const FriendsListItem = ( props: FriendsListItemProps ) => {
const { user } = props;
return (
<TouchableWithoutFeedback>
<View style={styles.container}>
<View style={styles.lefContainer}>
<Image source={{ uri: user.imageUri }} style={styles.avatar}/>
<View style={styles.midContainer}>
<Text style={styles.username}>{user.name}</Text>
<Text numberOfLines={2} style={styles.status}>{user.email}</Text>
</View>
</View>
</View>
</TouchableWithoutFeedback>
);
}
export default FriendsListItem;
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
width: "100%",
justifyContent: 'space-between',
//height: '100%',
},
lefContainer: {
flexDirection: 'row',
padding: 16,
},
midContainer: {
justifyContent: 'space-around'
},
avatar: {
width: 60,
height: 60,
borderRadius: 50,
marginRight: 15,
},
username: {
fontWeight: 'bold',
fontSize: 16,
},
status: {
fontSize: 16,
color: 'grey',
},
});
Looking at the code example, in your FriendsListItem component, any time you use your "user" prop, you need to change it. For example, change this:
user.imageUri
to this:
user.item.imageUri
What you are passing in is an object (e.g. user), which then contains another object (e.g. item), which finally contains your data (e.g. imageUri).
I figured it out. Turns out I am just an idiot. The expo app on my phone was logged into a different account so that's why it wasn't showing any friends for that user.

FlatList not rendering row

I am trying to learn FlatList component of react-native. Observing a tutorial, I have implemented a sample applications which list components inside a scrollview. I am trying to replace scrollview with FlatList, but items are not renderings on the screen. I have included the main source code here.
App.js
import React, { Component } from 'react'
import {
StyleSheet,
View,
ScrollView,
FlatList
} from 'react-native'
import ColorButton from './components/ColorButton'
class App extends Component {
constructor() {
super()
this.state = {
backgroundColor: 'blue'
}
this.changeColor = this.changeColor.bind(this)
}
changeColor(backgroundColor) {
this.setState({backgroundColor})
}
render() {
const { backgroundColor } = this.state
return(
<FlatList
data = {'red', 'green', 'salmon'}
renderItem = {(color) => {
<ColorButton backgroundColor={color} onSelect={this.changeColor}></ColorButton>
} } />
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 20
}
})
export default App
ColorButton.js
import React from 'react'
import {
StyleSheet,
Text,
View,
TouchableHighlight
} from 'react-native'
const ColorButton = ({ backgroundColor, onSelect=f=>f }) => (
<TouchableHighlight
style = {styles.button}
onPress={() => onSelect(backgroundColor)}
underlayColor="orange">
<View style = {styles.row}>
<View style = {[styles.sample, {backgroundColor}]} />
<Text style = {styles.text}>backgroundColor</Text>
</View>
</TouchableHighlight>
)
const styles = StyleSheet.create({
button: {
margin: 10,
padding: 10,
borderWidth: 2,
borderRadius: 10,
alignSelf: 'stretch',
backgroundColor: 'rgba(255,255,255,0.8)'
},
row: {
flexDirection: 'row',
alignItems: 'center'
},
sample: {
height: 20,
width: 20,
borderRadius: 10,
margin: 5,
backgroundColor: 'white'
},
text: {
fontSize: 30,
margin: 5
}
})
export default ColorButton
Change your code for flatlist to the one below :
<FlatList
data = {['red', 'green', 'salmon']}
renderItem = {({item}) => {
<ColorButton backgroundColor={item} onSelect={this.changeColor}>
</ColorButton>
} } />
Hope it helps. feel free for doubts

React native SectionList not updating

I am developing a sample app as part of learning react-native, in which it has a ColorForm that accepts the value from a TextInput and with the help of Props, the data will be sent to the Main view, such as App. The App has a SectionList that doesn't update with the new value inputs from ColorForm.
Following is the source code that I have used:
App.js
import React, { Component } from 'react'
import {
StyleSheet,
SectionList,
Text,
Alert
} from 'react-native'
import ColorButton from './components/ColorButton'
import ColorForm from './components/ColorForm'
class App extends Component {
constructor() {
super()
this.state = {
backgroundColor: 'blue',
availableColors: ['red', 'green', 'yellow', 'pink']
}
this.changeColor = this.changeColor.bind(this)
this.newColor = this.newColor.bind(this)
}
changeColor(backgroundColor) {
this.setState({ backgroundColor })
}
newColor(color) {
const colors = [
...this.state.availableColors,
color
]
this.setState(colors)
}
render() {
const { backgroundColor, availableColors } = this.state
return (
<SectionList style={styles.list}
backgroundColor={backgroundColor}
sections={[{ title: "Header", data: availableColors }]}
renderSectionHeader={({ section }) => (
<ColorForm onNewColor={this.newColor} />
)}
renderItem={({ item }) => (
<ColorButton backgroundColor={item} onSelect={this.changeColor} />
)}
keyExtractor={(item, index) => index}
/>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 20
},
list: {
marginTop: 40
}
})
export default App
ColorForm.js
import React, { Component } from 'react'
import {
View,
Text,
StyleSheet,
TextInput
} from 'react-native'
import PropTypes from 'prop-types'
export default class ColorForm extends Component {
constructor() {
super()
this.state = {
txtColor: ''
}
this.submit = this.submit.bind(this)
}
submit() {
this.props.onNewColor(this.state.txtColor.toLowerCase())
this.setState({ txtColor: '' })
}
render() {
return (
<View style={styles.container}>
<TextInput
style={styles.txtInput}
placeholder="Enter a color..."
onChangeText={(txtColor) => this.setState({ txtColor })}
value={this.state.txtColor}
/>
<Text style={styles.button} onPress={this.submit}>Add</Text>
</View>
)
}
}
ColorForm.propTypes = {
onNewColor: PropTypes.func.isRequired
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'space-around',
backgroundColor: 'lightgrey',
height: 70,
paddingTop: 20
},
txtInput: {
flex: 1,
margin: 5,
padding: 5,
borderWidth: 2,
fontSize: 20,
borderRadius: 5,
backgroundColor: 'snow'
},
button: {
backgroundColor: 'darkblue',
margin: 5,
padding: 5,
alignItems: 'center',
justifyContent: 'center',
color: 'white',
fontSize: 20
}
})
Can anyone help me to sort out the issue? Thanks in advance.
It looks like the state is not being updated in your method newColor, since availableColors is an array u can use push operation to add new value to the array update the code as below and it will work.
newColor(color) {
console.log('adding', color)
const colors = this.state.availableColors
colors.push(color)
this.setState(colors)
}

react-native useState error ("is read-only")

When running the code below in react-native, I get a "buttonColor is read-only" error.
I've been reviewing documentation from various places on useState but am still not sure what is causing this particular error.
I would expect for the button to alternate between 'green' (the initial state) and 'red' after each subsequent tap, but it just show green on the first render and then I get the error message after the first tap.
import React, {useState} from 'react';
import {StyleSheet, Text, View, TouchableOpacity} from 'react-native';
const ColorSquare = () => {
const[buttonColor, setColor] = useState('green');
const changeColor = () => {
if (buttonColor='green') {
setColor('red')
} else if (buttonColor='red') {
setColor('green')
} else {
setColor('blue')
}
}
return (
<View style={styles.container}>
<TouchableOpacity
style={{backgroundColor:buttonColor, padding: 15}}
onPress={()=>changeColor()}
>
<Text style={styles.text}>Change Color!</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
text:{
color:'white'
},
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff',
},
});
export default ColorSquare;
Problem is you are assigning the value of button color instead of comparing it i.e using = instead of ===. You are basically setting a value to button color which is wrong.
import React, {useState} from 'react';
import {StyleSheet, Text, View, TouchableOpacity} from 'react-native';
const ColorSquare = () => {
const[buttonColor, setColor] = useState('green');
const changeColor = () => {
if (buttonColor==='green') { // use === instead of == //
setColor('red')
} else if (buttonColor==='red') { // use === instead of == //
setColor('green')
} else {
setColor('blue')
}
}
return (
<View style={styles.container}>
<TouchableOpacity
style={{backgroundColor:buttonColor, padding: 15}}
onPress={()=>changeColor()}
>
<Text style={styles.text}>Change Color!</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
text:{
color:'white'
},
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff',
},
});
export default ColorSquare;
In addition to the answer posted by Atin above, I also thought of a way to do this using numerical values and an array of colors which I ultimately chose to go with due to needing some underlying binary representation of the data.
import React, {useState} from 'react';
import {StyleSheet, Text, View, TouchableOpacity} from 'react-native';
const ColorSquare = () => {
const[buttonNumber, setNumber] = useState(0);
const colors = ['green','red']
const changeColor = () => {
if (buttonNumber<1) {
setNumber(buttonNumber => buttonNumber + 1)
} else {
setNumber(buttonNumber => buttonNumber - 1)
}
}
return (
<View style={styles.container}>
<TouchableOpacity
style={{backgroundColor:colors[buttonNumber], padding: 15}}
onPress={()=>changeColor()}
>
<Text style={styles.text}>Change Color!</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
text:{
color:'white'
},
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff',
},
});
export default ColorSquare;
HI there if you are in 2021 having this problem I want to show you something that I was doing wrong
In my case I was trying to use a handleChange function to setState look here below
const handleChange = (e) => {
setCustomerLogin({...customerLogin, [e.target.name]: e.target.value})
I was getting a setCustomerLogin is ready only and its because I wrapped the (e) in the above example.
Solution is
const handleChange = e => {
setCustomerLogin({...customerLogin, [e.target.name]: e.target.value})

Force unmounting on screen change

I recently integrated React Redux and Redux Thunk into my application in the hope that it would better allow me to manage state across screens.
However, using my navigation library (react native router flux), when ever I navigate between screens I get warnings of trying to set state across unmounted components and I am not sure what I would even need to unmount in componentWillUnmount as no calls should happen after a screen navigation.
My question then is, how can I force unmount everything on componentWillUnmount? Is there something built into React Native that I should use? Or, in my navigation library?
import React, { Component } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import * as Font from 'expo-font'
class CustomText extends Component {
async componentDidMount() {
await Font.loadAsync({
'varelaround-regular': require('../../../assets/fonts/varelaround-regular.ttf'),
'opensans-regular': require('../../../assets/fonts/opensans-regular.ttf'),
'opensans-bold': require('../../../assets/fonts/opensans-bold.ttf'),
});
this.setState({ fontLoaded: true });
}
state = {
fontLoaded: false,
};
setFontType = type => {
switch (type) {
case 'header':
return 'varelaround-regular';
case 'bold':
return 'opensans-bold';
default:
return 'opensans-regular';
}
};
render() {
const font = this.setFontType(this.props.type ? this.props.type : 'normal');
const style = [{ fontFamily: font }, this.props.style || {}];
const allProps = Object.assign({}, this.props, { style: style });
return (
<View>
{
this.state.fontLoaded ? (
<Text {...allProps}>{this.props.children}</Text>
) : <Text></Text>
}
</View>
);
}
}
export default CustomText;
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
}
});
And one of my screens:
import React from "react";
import { ActivityIndicator, Image, StyleSheet, View } from "react-native";
import { Actions } from "react-native-router-flux";
import { connect } from "react-redux";
import * as profile from "../actions/profile";
import {
CustomText
} from "../components/common/";
class Home extends React.Component {
componentDidMount() {
this.props.loadProfile();
}
renderScreen() {
return (
<View style={{ flex: 1 }}>
<View style={{ flex: 0.3 }}>
<CustomText type="header" style={styles.headerTextStyle} onPress={() => Actions.home()}>
Hello {this.props.name}!
</CustomText>
</View>
</View>
);
}
renderWaiting() {
return (
<GradientBackground type="purple">
<View
style={{ flex: 1, justifyContent: "center", alignItems: "center" }}
>
<ActivityIndicator size="large" color="#FFF" />
</View>
</GradientBackground>
);
}
render() {
return (
<View style={{ flex: 1 }}>
{this.props.isLoading == true
? this.renderWaiting()
: this.renderScreen()}
</View>
);
}
}
function mapStateToProps(state) {
return {
name: state.profile.profile.friendly_name,
isLoading: state.profile.isLoading,
error: state.profile.error
};
}
function mapDispatchToProps(dispatch) {
return {
loadProfile: () => dispatch(profile.loadProfile())
};
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Home);
const styles = StyleSheet.create({
headerTextStyle: {
color: "#FFFFFF",
fontSize: 40,
textAlign: "center",
marginVertical: 50
},
basicViewStyle: {
flex: 1
}
});