reactjs - 作为道具传递的函数不是函数
问题描述
我正在尝试创建一个登录模块。我有一个 LoginView,它定义了视图和一个 LoginController,我在其中定义了所有用户交互。现在我正在尝试合并一个逻辑,在该逻辑中,LoginController 将更改 LoginView 的状态,例如将 isLoading 的值从 false 更改为 true,以防所有输入数据都有效
登录视图
import React, { Component, Fragment} from 'react';
import LoginController from '../Controller/LoginController.js';
import {
View,
ScrollView,
StatusBar,
SafeAreaView,
TextInput,
TouchableOpacity,
Text,
StyleSheet
} from 'react-native';
const styles = StyleSheet.create({
container: {
paddingTop: 23
},
input: {
margin: 15,
height: 40,
borderColor: '#7a42f4',
borderWidth: 1
},
submitButton: {
backgroundColor: '#7a42f4',
padding: 10,
margin: 15,
height: 40,
},
submitButtonText:{
color: 'white'
}
});
export default class LoginView extends Component {
constructor(){
super()
this.state = {
isLoading: false
}
}
changeLoadingState = (currentLoadingState) => {
/* Create a loader screen and incorporate it here.
*/
this.setState({isLoading: currentLoadingState} , () => {
console.log("This is called when this.setState has resolved");
console.log(this.state.isLoading);
});
}
render() {
const con = new LoginController(this.changeLoadingState);
return (
<Fragment>
<StatusBar barStyle="dark-content" />
<SafeAreaView>
<View style = {styles.container}>
<TextInput style = {styles.input}
underlineColorAndroid = "transparent"
placeholder = "Email"
placeholderTextColor = "#9a73ef"
autoCapitalize = "none"
onChangeText = {con.handleEmail}/>
<TextInput style = {styles.input}
underlineColorAndroid = "transparent"
placeholder = "Password"
placeholderTextColor = "#9a73ef"
autoCapitalize = "none"
onChangeText = {con.handlePassword}/>
<TouchableOpacity
style = {styles.submitButton}
onPress = {
() => con.login()
}>
<Text style = {styles.submitButtonText}> Submit </Text>
</TouchableOpacity>
</View>
</SafeAreaView>
</Fragment>
);
}
}
登录控制器.js
import React, { Component } from 'react';
import LoginNetworkManager from '../NetworkManager/LoginNetworkManager.js';
import Loader from '../../Utils/Loader.js';
export default class LoginController extends Component {
constructor(props) {
super(props);
this.state = {
email: null,
password: null
};
this.changeLoadingState = this.changeLoadingState.bind(this);
}
changeLoadingState = (currentLoadingState) => {
this.props.changeLoadingState(currentLoadingState);
}
handleEmail = (text) => {
this.setState({email: text});
}
handlePassword = (text) => {
this.setState({password: text});
}
login = () => {
this.changeLoadingState(this.validate());
if (this.validate() == true) {
// Here in we will call the API
} else {
console.log(" It's false ");
// Do nothing
}
}
validate = () => {
var reg = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/;
var isValid = reg.test(this.email);
if (isValid) {
isValid = (this.password.trim().length > 0);
}
console.log(" Tis is Valid " + isValid);
return isValid
}
}
点击登录按钮时的错误是
_this.props.changeLoadingState is not a function
handleException @ ExceptionsManager.js:86
handleError @ setUpErrorHandling.js:23
reportFatalError @ error-guard.js:42
__guard @ MessageQueue.js:345
callFunctionReturnFlushedQueue @ MessageQueue.js:105
(anonymous) @ debuggerWorker.js:80
解决方案
这里的问题LoginController
是不是 a Component
,如果你只想成为一个助手类,那么你应该从中LoginController
删除state
and :props
export default class LoginController {
changeLoadingState = (currentLoadingState) => {
}
handleEmail = (text) => {
}
handlePassword = (text) => {
}
login = () => {
this.changeLoadingState(this.validate());
if (this.validate() == true) {
// Here in we will call the API
} else {
console.log(" It's false ");
// Do nothing
}
}
validate = () => {
var reg = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/;
var isValid = reg.test(this.email);
if (isValid) {
isValid = (this.password.trim().length > 0);
}
console.log(" Tis is Valid " + isValid);
return isValid
}
}
但是,如果您的目标是抽象有状态逻辑,那么您做错了。当你React.Component
从一个类扩展时,你明确告诉 React 这个类是一个Component
因此它应该返回JSX
(render()) 并且应该被初始化为一个 Component: <LoginController />
,为了抽象有状态逻辑,你实际上有很多非常酷的选择:
高阶组件 (HOC)
这被视为您的用例,因为您希望将一些道具注入到LoginView
中,因此您可以将逻辑抽象为 HOC:
import React, { Component } from 'react';
import LoginNetworkManager from '../NetworkManager/LoginNetworkManager.js';
import Loader from '../../Utils/Loader.js';
export default withLogin = (ChildComponent) => {
return class LoginController extends Component {
constructor(props) {
super(props);
this.state = {
email: null,
password: null
};
this.changeLoadingState = this.changeLoadingState.bind(this);
}
/*
Your logic
*/
render(){
return <ChildComponent {...this.state} />
}
}
}
现在在LoginView
你里面 export 像这样: export default withLogin(LoginView)
andLoginController
的状态将在LoginView
's props:this.props.email
和this.props.password
当然,使用 HOC 可以完成的所有事情也可以使用renderProps
and来完成hooks
。
推荐阅读
- react-router - 嵌套的 React Route 导致父级重新挂载
- c++ - Dev C++ 提供一个输出,但 Visual Studio 代码为相同代码提供另一个输出
- c# - 如何在网络上统一复制 Transform.rotation(字节 [])?
- javascript - 使用 Ajax 调用处理超时
- firebase - 环境变量未通过 firebase Github CI 传递
- php - 如何对php多维数组进行排序
- batch-file - 我怎样才能立即开始所有这些
- javascript - TradeOgre API 总是返回“无效市场”
- python - “在 ubuntu 20.04 上运行 tensorflow 时无法加载动态库‘libcudnn.so.8’”
- sycl - 使用 hipSYCL / llvm 在 nvidia 上注册使用情况