React Native componentDidUpdate 道具未连接到主组件?
React Native componentDidUpdate props not connecting to main component?
当尝试向我的登录组件添加漂亮的 Lottie 动画时,我卡住了,因为在主组件文件上引用时,似乎无法识别 componentDidUpdate 中的道具。
来自 'this.props.isActive'(Lottie 组件)的 'isActive' 和 ''(主要组件文件)的 'isActive' 应该连接并触发动画,但不知何故它们没有。
Lottie组件代码
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;
`;
我正在尝试将其连接到的主要登录组件:
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;
`;
还有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 未在初始渲染时调用。因此,如果 isActive 属性开始时为真并且没有改变,那么它就不会触发你的动画。
<Success isActive={true} />
如果您希望动画在第一次渲染时播放,那么您还需要在 componentDidMount
中触发动画。
或者您可以重构以使用函数组件和挂钩。
useEffect(()=> {
// animation code
}, [isActive])
当尝试向我的登录组件添加漂亮的 Lottie 动画时,我卡住了,因为在主组件文件上引用时,似乎无法识别 componentDidUpdate 中的道具。
来自 'this.props.isActive'(Lottie 组件)的'isActive' 和 ''(主要组件文件)的 'isActive' 应该连接并触发动画,但不知何故它们没有。
Lottie组件代码
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;
`;
我正在尝试将其连接到的主要登录组件:
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;
`;
还有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 未在初始渲染时调用。因此,如果 isActive 属性开始时为真并且没有改变,那么它就不会触发你的动画。
<Success isActive={true} />
如果您希望动画在第一次渲染时播放,那么您还需要在 componentDidMount
中触发动画。
或者您可以重构以使用函数组件和挂钩。
useEffect(()=> {
// animation code
}, [isActive])