function sumbit_Login(val, val1, nav) {
const we = val.length
const we1 = val1.length
if (we <= 15) {
alert('Invaild Email')
return (
<View style={{ width: 50000, height: 50000, backgroundColor: 'red' }}>
</View>
)
}
if (we1 <= 5) {
alert('Invaild Password')
return 0;
}
else {
nav.navigate('Main')
}
// I use it here out the function (inside another function)
<View style={{ marginBottom: 10, width: "80%", marginLeft: '10%', marginTop: '-8%' }}>
<Button
title="Login"
onPress={() => sumbit_Login(value, value1, navigation)}
/>
</View>
The view doesn't work in if statement anyone have another way or solve the problem i use the function inside a button but the 'View' inside return doesn't work (I don't get any error.)
You're not using the View anywhere in the component tree, try to trace your code, you're calling a function onPress, which is a callback and isn't really inside your render hierarchy, if I understand your use case correctly, you're doing this the wrong way..
The way that should be done is to have a state control the visibility of the view when you want to render it and when you don't, here's an example:
function SomeComponent({ navigation }) {
// Create a state for the visiblity
const [visible, setVisible] = useState(false)
function onSubmit(val, val1) {
const we = val.length
const we1 = val1.length
if (we <= 15) {
alert('Invaild Email')
// Set visiblity to true in order to show the View
setVisible(true)
return
}
if (we1 <= 5) {
alert('Invaild Password')
return;
}
else {
navigation.navigate('Main')
}
}
return (
<View style={{ marginBottom: 10, width: "80%", marginLeft: '10%', marginTop: '-8%' }}>
<Button
title="Login"
onPress={() => sumbit_Login(value, value1, navigation)}
/>
{
// Conditionally render the View
visible && <View style={{ width: 50000, height: 50000, backgroundColor: 'red' }}>
}
</View>
)
}
I suggest you read more docs about react and react native, dos and don'ts, and the best practices for dealing with the lifecycle
Hope you find this helpful
Related
I'm facing a weird problem. In my react native app I have customAlert, which shows if the statement is false, currently it shows only the console.
I tried testing and showing my CustomAlert but not inside onPress it works fine like the image below. but inside onPress does not work. What am I missing here?
import CustomAlert from '../components/CustomAlert';
const [modalVisible, setModalVisible] = useState(false);
<View style={{ marginTop: `30%`, alignItems: 'center' }}>
<GoogleSigninButton
style={{ width: 252, height: 58 }}
size={GoogleSigninButton.Size.Wide}
color={GoogleSigninButton.Color.Dark}
onPress={() => {
if (fingerprint === true) {
googleLogin();
}
else {
console.log("Alert should pop up");
<CustomAlert
modalVisible={modalVisible}
setModalVisible={setModalVisible}
title={'Message'}
message={'Please enable your Touch ID/PIN to your device'}
buttons={[{
text: 'Ok',
func: () => { console.log('Yes Pressed') }
}]}
/>
}
}
}
/>
</View>
You could try moving your <CustomAlert> outside of the <GoogleSignInButton> and then display the <CustomAlert> conditionally based on your modalVisible state variable:
import CustomAlert from '../components/CustomAlert';
const [modalVisible, setModalVisible] = useState(false);
<View style={{ marginTop: `30%`, alignItems: 'center' }}>
<GoogleSigninButton
style={{ width: 252, height: 58 }}
size={GoogleSigninButton.Size.Wide}
color={GoogleSigninButton.Color.Dark}
onPress={() => {
if (fingerprint === true) {
googleLogin();
}
else {
console.log("Alert should pop up");
setModalVisible(true);
}
}
}
/>
<CustomAlert
modalVisible={modalVisible}
setModalVisible={setModalVisible}
title={'Message'}
message={'Please enable your Touch ID/PIN to your device'}
buttons={[{
text: 'Ok',
func: () => { console.log('Yes Pressed') }
}]}
/>
</View>
Notice that inside the else branch we call setModalVisible(true) which will set modalVisible to true. Then modalVisible gets passed as a prop to <CustomAlert>, which should tell the modal to render (assuming it is set up properly).
I want it to play only when the card is selected, if the card is not selected it simply displays the lottie file but nothing is being played. Right now I get an error of cannot read property 'play' of null. When I remove the animationPress() and get the file to run it also start at the mentioned initialSegment that I'm passing into it.
What am I doing wrong here?
My card that the Lottie file is in:
const animation = useRef(null);
const animationPress = () => {
animation.current.play();
}
return(
{filteredData.map((item, index) => {
return (
<>
<TouchableOpacity onPress={() => setSelected(item), animationPress()}>
<View style={[{ alignItems: 'center' }, selected.id == item.id ? { paddingTop: 10 } : { paddingTop: 20 }]}>
<CardioCard style={selected.id == item.id ? { backgroundColor: 'green', fontFamily: 'ssb_SemiBold' } : {}} >
<CardItem style={[styles.card, selected.id == item.id ? { backgroundColor: 'green' } : {}]}>
<Text>
< LottieView
ref={animation}
source={require('../../assets/images/heartbeat.json')}
initialSegment={68,135}
autoPlay={true}
loop={true}
style={{ width: 100, height: 100 }} />
</Text>
</CardItem>
</CardioCard>
<Text style={[{ fontSize: 18, color: 'hsl(98, 0%, 11%)', paddingLeft: 15 }, selected.id == item.id ? { fontFamily: 'ssb_SemiBold' } : {}]}>{item.name}</Text>
</View>
</TouchableOpacity>
</>
)
})}
...
)
Edit
I also tried to do useState for the autoplay and loop button so they would be false but when the button is pressed it would turn true but the animation wouldn't load even after the button press.
const [playAnimation, setPlayAnimation] = useState(false);
<TouchableOpacity onPress={() => setPlayAnimation(true)}>
<LottieView
source={require('../../assets/images/heartbeat.json')}
autoPlay={playAnimation}
loop={playAnimation}
style={{ width: 100, height: 100 }}
/>
</TouchableOpacity>
this is driving me nuts and idk what to do anymore.
I'm new to react-native but I guess it's like react. Not sure to correctly understand the issue.
In this case, shouldn't you use animation.current instead of animation as your lottieView ref? or at least ensure that your ref animation is defined (not null) so that the container can be mounted even if not launched, this is also for your animationPress function. Also you should disable the autoPlay I guess (since you want to trigger the animation with a button).
< LottieView
ref={animation.current}
source={require('../../assets/images/heartbeat.json')}
initialSegment={68,135}
autoPlay={false}
loop={true}
style={{ width: 100, height: 100 }} />
or
{animation && < LottieView
ref={animation}
source={require('../../assets/images/heartbeat.json')}
initialSegment={68,135}
autoPlay={false}
loop={true}
style={{ width: 100, height: 100 }} />}
And of course
const animationPress = () => {
if(animation?.current) {
animation.current.play();
}
}
Hello I've been looking through several threads on stackoverflow but I haven't been able to solve my problem. I have an app where you can save movies to a watchlist. On this specific screen I want to display a users watchlist and give them the ability to delete it from the list. Currently the function is indeed deleting the movie from the list and removing it from firebase but i can't get my screen to rerender to visually represent the deletion.
This is the code right now:
export default function MovieWatchlistTab(props: any) {
let { movies } = props;
let movieWatchlist: any[] = [];
const [watchlistSnapshot, setWatchlistSnapshot] = useState();
const user: firebase.User = auth().currentUser;
const { email } = user;
const watchlistRef = firestore().collection("Watchlist");
useEffect(() => {
getWatchlistSnapshot();
}, []);
const getWatchlistSnapshot = async () => {
setWatchlistSnapshot(await watchlistRef.where("userId", "==", email).get());
};
const convertDataToArray = () => {
const convertedMovieList = [];
for (let movie in movies) {
let newMovie = {
backdrop: movies[movie].backdrop,
overview: movies[movie].overview,
release: movies[movie].release,
title: movies[movie].title,
};
convertedMovieList.push(newMovie);
}
movieWatchlist = convertedMovieList;
};
const renderMovieList = () => {
convertDataToArray();
return movieWatchlist.map((m) => {
const handleOnPressDelete = () => {
const documentRef = watchlistRef.doc(watchlistSnapshot.docs[0].id);
const FieldValue = firestore.FieldValue;
documentRef.set(
{
movies: {
[m.title]: FieldValue.delete(),
},
},
{ merge: true }
);
movieWatchlist.splice(
movieWatchlist.indexOf(m),
movieWatchlist.indexOf(m) + 1
);
console.log("movieWatchlist", movieWatchlist);
};
const swipeButtons = [
{
text: "Delete",
color: "white",
backgroundColor: "#b9042c",
onPress: handleOnPressDelete,
},
];
return (
<Swipeout right={swipeButtons} backgroundColor={"#18181b"}>
<View key={m.title} style={{ marginTop: 10, flexDirection: "row" }}>
<Image
style={{ height: 113, width: 150 }}
source={{
uri: m.backdrop,
}}
/>
<View>
<Text
style={{
flex: 1,
color: "white",
marginLeft: 10,
fontSize: 17,
}}
>
{m.title}
</Text>
<Text style={{ flex: 1, color: "white", marginLeft: 10 }}>
Release: {m.release}
</Text>
</View>
</View>
</Swipeout>
);
});
};
return (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#18181b",
}}
>
<ScrollView
style={{ flex: 1 }}
contentContainerStyle={{
width: Dimensions.get("window").width,
}}
>
{renderMovieList()}
</ScrollView>
</View>
);
}
I've been trying to play around with useStates and I think the answer is in that direction but I just can't seem to get it to work anyway. Any help would be appreciated!
There are a few lines in your code that show a misunderstand of React state. You have a value let movieWatchlist: any[] = []; that you reassign in convertDataToArray() and mutate in handleOnPressDelete. That's just not how we do things in React and it's not going to trigger updates properly. movieWatchlist either needs to be a stateful variable created with useState.
Do the movies passed in through props change? If they do, then you don't need to store them in state here. You could just return an array from convertDataToArray() rather than setting a variable and returning void.
To be honest it's really not clear what convertDataToArray is even doing as it seems like newMovie is either the same or a subset of the original movie object. If the point is to remove the other properties aside from these four, that's not actually needed. If the prop movies is already an array, just delete this whole function and use movies directly. If it's a keyed object, use Object.values(movies) to get it as an array.
I'm thoroughly confused as to what we are getting from props and what we are getting from firebase. It seems like we would want to update the snapshot state after deletion, but you only run your useEffect once on mount.
You may still have errors, but this code should be an improvement:
interface Movie {
backdrop: string;
overview: string;
release: string;
title: string;
}
const MovieThumbnail = (props: Movie) => (
<View key={props.title} style={{ marginTop: 10, flexDirection: "row" }}>
<Image
style={{ height: 113, width: 150 }}
source={{
uri: props.backdrop
}}
/>
<View>
<Text
style={{
flex: 1,
color: "white",
marginLeft: 10,
fontSize: 17
}}
>
{props.title}
</Text>
<Text style={{ flex: 1, color: "white", marginLeft: 10 }}>
Release: {props.release}
</Text>
</View>
</View>
);
export default function MovieWatchlistTab() {
const [watchlistSnapshot, setWatchlistSnapshot] = useState<DocumentSnapshot>();
const user: firebase.User = auth().currentUser;
const { email } = user;
const watchlistRef = firestore().collection("Watchlist");
const getWatchlistSnapshot = async () => {
const results = await watchlistRef.where("userId", "==", email).get();
setWatchlistSnapshot(results.docs[0]);
};
useEffect(() => {
getWatchlistSnapshot();
}, []);
const deleteMovie = async (title: string) => {
if ( ! watchlistSnapshot ) return;
const documentRef = watchlistRef.doc(watchlistSnapshot.id);
const FieldValue = firestore.FieldValue;
await documentRef.set(
{
movies: {
[title]: FieldValue.delete()
}
},
{ merge: true }
);
// reload watch list
getWatchlistSnapshot();
};
// is this right? I'm just guessing
const movies = ( watchlistSnapshot ? watchlistSnapshot.data().movies : []) as Movie[];
return (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#18181b"
}}
>
<ScrollView
style={{ flex: 1 }}
contentContainerStyle={{
width: Dimensions.get("window").width
}}
>
{movies.map((m) => (
<Swipeout
right={[
{
text: "Delete",
color: "white",
backgroundColor: "#b9042c",
// need to pass the title to the delete handler
onPress: () => deleteMovie(m.title)
}
]}
backgroundColor={"#18181b"}
>
<MovieThumbnail {...m} />
</Swipeout>
))}
</ScrollView>
</View>
);
}
I want some guidance how to make it possible to swipe between react native elements "Buttongroups".
I found a "swiper" library but cant make it work with the buttongroup.
https://github.com/leecade/react-native-swiper
Have anyone any idé how to implement this ?
I want to be able to both swipe and push one of the buttons.
My Component including ButtonGroup :
class Users extends Component {
constructor () {
super()
this.state = {
selectedIndex: 0,
loading: false
}
this.updateIndex = this.updateIndex.bind(this)
}
// Call fetchList with 0 to get access to all users
componentWillMount () {
let i = 0
this.props.fetchList(i)
this.props.fetchProfileData()
}
// updates the selectedIndex and calls the methods with the selectedindex
updateIndex (selectedIndex) {
this.setState({selectedIndex})
this.fetchAllUsers(selectedIndex)
this.fetchFemale(selectedIndex)
this.fetchMale(selectedIndex)
}
fetchAllUsers (index) {
if (index === 0) {
this.props.fetchList(index)
}
}
fetchFemale (index) {
if (index === 1) {
this.props.fetchList(index)
}
}
fetchMale (index) {
if (index === 2) {
this.props.fetchList(index)
}
}
renderItem ({ item }) {
return <ListUserItem user={item} />
}
render () {
const buttons = ['All', 'Female', 'Male']
const { selectedIndex } = this.state
return (
<ImageBackground
source={require('../../assets/image.jpg')}
style={styles.container}
>
<HeaderBlack />
<View>
<BlurView
style={styles.absolute}
blurType='dark'
blurAmount={0.001}
height={695} />
<View style={{ justifyContent: 'center', alignItems: 'center' }} >
<ButtonGroup
onPress={this.updateIndex.bind(this)}
selectedIndex={selectedIndex}
selectedButtonStyle={{backgroundColor: 'black'}}
buttons={buttons}
containerStyle={{ backgroundColor: 'transparent', height: 23, width: 200, marginTop: 30, marginBottom: -20, justifyContent: 'center', alignItems: 'baseline' }}
textStyle={{fontFamily: 'GeosansLight', color: 'white'}} />
</View>
<View style={{ maxHeight: 580, marginTop: 50 }} >
<FlatList
data={this.props.users}
renderItem={this.renderItem}
/>
</View>
</View>
</ImageBackground>
)
}
}
I usually use hammer.js for any swipe interactions I need to manage. Essentially this library just has you create custom event listeners for things like swiping, panning, pinching, rotating, etc. and just attach them to whatever element you'd like. As long as you have a reference to the element, it shouldn't matter if it is a react element or not, it should work just the same.
I am using React Native and React Navigation to build a simple app.
I have got the basic structure working with stub state but I am having problem with changing state via callback and re-render.
In my screen, I have simple start button
`<View style={styles.buttonContainer}>
<TouchableOpacity
style={[myStyles.buttonStyle, { backgroundColor: color }]}
onPress={() => handlePress(button.title)}
>
<Text style={myStyles.textStyle}>{button.title}</Text>
</TouchableOpacity>
</View>`
Problem:
After I update my parent Component state, my child component does not instantly render to match the state change. I understood React will re-render all child components when parent state is changed?
Instead, I have to move back to previous screen and navigate again to my button screen to see that the button's color and text has changed correctly.
I've read about requiring a componentWillReceiveProps(nextProps) handler but I am not sure how to use it. I put a console.log('nextProps', nextProps) inside but it does not get fired.
From navigation perspective, the Root component is on index[0] and my button view is at index[3] so it's the 3rd screen from the root.
EDIT 1: Added Code
myButton screen:
export class TeamsScreen extends React.Component {
static navigationOptions = ({ navigation }) => ({
title: `${navigation.state.params.game.name}: Select Team`,
headerTintColor: 'white',
headerStyle: {
backgroundColor: 'black',
},
headerVisible: true
})
componentWillReceiveProps(nextProps) {
console.log('nextProps', nextProps);
}
render() {
const { navigate, setParams } = this.props.navigation;
const { game, player, setGameState } = this.props.navigation.state.params;
const color = game.status === 'Start' ? 'green' : 'red';
const index = game.indexOf(player);
const status = game.status;
console.log('index', index);
console.log('status', status);
return (
<View style={styles.container}>
<View style={styles.buttonContainer}>
<TouchableOpacity
style={[myStyles.buttonStyle, { backgroundColor: color }]}
onPress={() => setGameState(index, status)}
>
<Text style={myStyles.textStyle}>{game.status}</Text>
</TouchableOpacity>
</View>
<View style={styles.buttonContainer}>
<Button
onPress={() => navigate('ChangeDriverScreen', { team, game })}
title='Change Driver'
/>
</View>
<View style={{ marginTop: 40, marginBottom: 20 }}>
<Text style={{ fontSize: 16, color: 'white', alignSelf: 'center' }}>Teams</Text>
</View>
<View style={{ height: 250 }}>
<FlatList
data={player.teams}
renderItem={({item}) =>
<View style={styles.buttonContainer}>
<Button
onPress={() => navigate('TeamSelectedStartScreen', { team: item })}
title={item.name}
/>
</View>}
keyExtractor={item => item.name}
/>
</View>
<Image
style={{ alignSelf: 'center', justifyContent: 'flex-end', height: 75, width: 250, resizeMode: 'stretch'}}
source={require('./images/icons/playerPlaceholder.png')}
/>
</View>
)}}
Then the onPress function that is called back:
setGameState = (gameIndex, status) => {
console.log('setGameState', gameIndex, status);
console.log('gameStateBefore', this.state.game);
const newGameState = this.state.game.map(t => {
console.log(this.state.game.indexOf(t));
if (this.state.game.indexOf(t) === gameIndex) {
const newStatus = status === 'Start' ? 'Stop' : 'Start';
t.status = newStatus; /*eslint no-param-reassign: "off"*/
console.log('inside if', t.status);
console.log('inside if game', t);
return t;
}
return t;
});
console.log('new Game State', newGameState);
this.setState(() => ({
game: newGameState
}));
}
So the setState method works (as re-navigating back to screen 3 shows the correct state but core question is how to get immediate re-render of screen 3 when setState is called from Screen 0.