When trying to add a nice Lottie animation to my Login component, I got stuck because the props inside componentDidUpdate don't seem to be recognised when referenced on the main component file.
'isActive' from 'this.props.isActive'(the Lottie component) and 'isActive' from ''(the main component file) should connect and trigger the animation, but somehow they don't.
The Lottie component code
import React from "react";
import styled from "styled-components";
import LottieView from "lottie-react-native";
import { Animated, Dimensions } from "react-native";
const ScreenHeight = Dimensions.get("window").height;
class Success extends React.Component {
state = {
top: new Animated.Value(0),
opacity: new Animated.Value(0),
};
componentDidMount() {}
componentDidUpdate() {
if (this.props.isActive) {
Animated.timing(this.state.top, { toValue: 0, duration: 0 }).start();
Animated.timing(this.state.opacity, { toValue: 1 }).start();
this.animation.play();
}
}
render() {
return (
<AnimatedContainer
style={{ top: this.state.top, opacity: this.state.opacity }}
>
<LottieView
source={require("../assets/checked-done.json")}
autoPlay={false}
loop={false}
ref={(animation) => {
this.animation = animation;
}}
/>
</AnimatedContainer>
);
}
}
export default Success;
const Container = styled.View`
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.9);
justify-content: center;
align-items: center;
position: absolute;
top: 0;
left: 0;
`;
And the main login component I am trying to connect it to:
import React from "react";
import styled from "styled-components";
import {
TouchableOpacity,
TouchableWithoutFeedback,
Keyboard,
} from "react-native";
import Success from "./Success";
class ModalLogin extends React.Component {
state = {
email: "",
password: "",
isSuccessful: false,
};
handleLogin = () => {
console.log(this.state.email, this.state.password);
};
tapBackground = () => {
Keyboard.dismiss();
};
render() {
return (
<TouchableWithoutFeedback onPress={this.tapBackground}>
<Container
style={{ backgroundColor: "grey" }}
ref={(n) => {
if (n && viewRef === null) {
setViewRef(findNodeHandle(n));
}
}}
>
<Modal>
<Logo source={require("../assets/logo.png")} />
<Text>Manage your lessons</Text>
<TextInput
onChangeText={(email) => this.setState({ email })}
placeholder="Email"
keyboardType="email-address"
/>
<TextInput
onChangeText={(password) => this.setState({ password })}
placeholder="Password"
secureTextEntry={true}
/>
<IconEmail source={require("../assets/icon-email.png")} />
<IconPassword source={require("../assets/icon-password.png")} />
<TouchableOpacity onPress={this.handleLogin}>
<Button>
<ButtonText>Login</ButtonText>
</Button>
</TouchableOpacity>
</Modal>
<Success isActive={true} />
</Container>
</TouchableWithoutFeedback>
);
}
}
export default ModalLogin;
const viewRef = styled.View``;
const Container = styled.View`
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.75);
justify-content: center;
align-items: center;
`;
const Modal = styled.View`
width: 335px;
height: 370px;
background: white;
border-radius: 20px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
align-items: center;
`;
const Logo = styled.Image`
width: 90px;
height: 90px;
margin-top: 8px;
margin-bottom: -8px;
`;
const Text = styled.Text`
margin-top: 20px;
font-size: 13px;
font-weight: 600;
text-transform: uppercase;
width: 160px;
text-align: center;
color: #b8bece;
`;
const TextInput = styled.TextInput`
border: 1px solid #dbdfea;
width: 295px;
height: 44px;
border-radius: 10px;
font-size: 17px;
color: #3c4560;
margin-top: 20px;
padding-left: 44px;
`;
const Button = styled.View`
background: #8dd2dc;
width: 295px;
height: 50px;
justify-content: center;
align-items: center;
border-radius: 10px;
margin-top: 20px;
`;
const ButtonText = styled.Text`
color: white;
font-weight: 600;
text-transform: uppercase;
`;
const IconEmail = styled.Image`
width: 30px;
height: 30px;
position: absolute;
top: 174px;
left: 31px;
`;
const IconPassword = styled.Image`
width: 23px;
height: 23px;
position: absolute;
top: 241px;
left: 35px;
`;
Also Package.json
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"eject": "expo eject"
},
"dependencies": {
"@react-native-community/masked-view": "0.1.6",
"@react-navigation/native": "^5.4.3",
"expo": "~37.0.3",
"lodash": "^4.17.15",
"lottie-react-native": "^3.4.0",
"native-base": "^2.13.12",
"react": "~16.9.0",
"react-dom": "~16.9.0",
"react-native": "https://github.com/expo/react-native/archive/sdk-37.0.1.tar.gz",
"react-native-blur": "ndbroadbent/react-native-blur#android-fix",
"react-native-calendars": "^1.265.0",
"react-native-gesture-handler": "~1.6.0",
"react-native-i18n": "^1.0.0",
"react-native-material-design": "^0.3.7",
"react-native-reanimated": "~1.7.0",
"react-native-safe-area-context": "0.7.3",
"react-native-screens": "~2.2.0",
"react-native-web": "~0.11.7",
"react-navigation": "^4.3.9",
"react-navigation-stack": "^2.5.1",
"react-navigation-tabs": "^2.8.13",
"react-redux": "^7.2.0",
"redux": "^4.0.5",
"styled-components": "^5.1.0"
},
"devDependencies": {
"@babel/core": "^7.8.6",
"babel-preset-expo": "~8.1.0"
},
"private": true
componentDidUpdate() is invoked immediately after updating occurs. This method is not called for the initial render. https://reactjs.org/docs/react-component.html#componentdidupdate
componentDidUpdate isn't called on the initial render. So if the isActive prop starts as true and doesn't change then it will not trigger your animation.
<Success isActive={true} />
If you want your animation to play on the first render then you will need to also trigger the animation in componentDidMount
.
Or you could refactor to use a function component and hooks.
useEffect(()=> {
// animation code
}, [isActive])