太多的重新渲染。 React 限制渲染次数以防止无限循环。使用上下文传递参数 API
Too many re-renders. React limits the number of renders to prevent an infinite loop. Passing parameters with context API
我正在使用 React context 获取 context provider 文件中定义的登录函数和错误以登录到 firebase 数据库,并使用登录时抛出的错误在应用程序中显示它。
我的问题是,当我只是使用从 firebase 身份验证抛出的错误来显示应用程序中的错误时,我没有收到任何错误,但我还添加了其他错误,如空字段,以在中显示错误字段应用程序。
这样做之后我得到了太多重新渲染的错误。我认为这个错误是由于在函数中使用了多个 if 语句。你能建议一个新的选项吗?如果这是错误的,请解释一下。
上下文提供程序文件
import React from 'react';
import auth from '@react-native-firebase/auth';
export const AuthContext = React.createContext();
export const AuthProvider = ({children}) => {
const [user, setUser] = React.useState(null);
const [error, setError] = React.useState('');
return (
<AuthContext.Provider
value={{
user,
setUser,
error,
login: async (email, pwd) => {
try {
await auth().signInWithEmailAndPassword(email, pwd);
} catch (e) {
setError(e);
}
},
register: async (email, pwd) => {
try {
await auth().createUserWithEmailAndPassword(email, pwd);
} catch (e) {
setError(e);
}
},
logout: async () => {
try {
await auth().signOut();
} catch (e) {
console.log(e);
}
},
}}>
{children}
</AuthContext.Provider>
);
};
应用文件
import React from 'react';
import {Button, Image, Text, TouchableOpacity, View} from 'react-native';
import styles from '../styles/Styles';
import FormInput from '../components/FormInput';
import FormButton from '../components/FormButton';
import SocialButton from '../components/SocialButton';
import {AuthContext} from '../navigation/AuthProvider';
import ErrorText from '../components/ErrorText';
const LoginScreen = ({navigation}) => {
const [email, setEmail] = React.useState('');
const [password, setPassword] = React.useState('');
const {login, error} = React.useContext(AuthContext);
const [errorForwarded, setErrorForwarded] = React.useState(null);
if (error) {
setErrorForwarded(error);
}
if (!email || !password) {
setErrorForwarded('fields-empty');
}
const renderErrorText = e => {
if (e.code === 'auth/invalid-email') {
return <ErrorText errorText="Email invalid!" />;
}
if (e.code === 'auth/user-not-found') {
return <ErrorText errorText="User not found!" />;
}
if (e.code === 'auth/wrong-password') {
return <ErrorText errorText="Wrong password!" />;
}
if (e === 'fields-empty') {
return <ErrorText errorText="Fields cannot be empty!" />;
}
};
return (
<View style={styles.loginContainer}>
<Image
source={require('../assets/rn-social-logo.png')}
style={styles.loginLogo}
/>
<Text style={styles.loginText}>Sign In</Text>
<FormInput
labelValue={email}
onChangeText={email => setEmail(email)}
placeholderText="Email"
iconType="user"
keyboardType="email-address"
autoCapitalize="none"
autoCorrect={false}
/>
<FormInput
labelValue={password}
onChangeText={pwd => setPassword(pwd)}
placeholderText="Password"
iconType="lock"
secureTextEntry={true}
/>
{error ? renderErrorText(errorForwarded) : null}
<FormButton
buttonTitle="Sign In"
onPress={() => {
{
email && password ? login(email, password) : {};
}
}}
/>
<TouchableOpacity style={styles.loginForgetBtn}>
<Text style={styles.loginNavBtnText}>Forgot Password?</Text>
</TouchableOpacity>
<SocialButton
buttonTitle="Sign In with Facebook"
buttonType="facebook-square"
color="#4867aa"
backgroundColor="#e6eaf4"
/>
<SocialButton
buttonTitle="Sign In with Google"
buttonType="google"
color="#de4d41"
backgroundColor="#f5e7ea"
/>
<TouchableOpacity
style={styles.loginForgetBtn}
onPress={() => navigation.navigate('Signup')}>
<Text style={styles.loginNavBtnText}>
Don't have an account? Create here...
</Text>
</TouchableOpacity>
</View>
);
};
export default LoginScreen;
您遇到多次重新呈现的原因与函数中的 if 条件无关。通过 运行 直接在组件函数内设置状态的函数,您将强制重新渲染,然后它开始从上到下 运行 函数,再次设置状态。
只有 React 钩子不是 reinitialized/run 并且可以在每次后续重新渲染时避免 运行ning,因此您需要使用带有依赖项数组的 useEffect()
钩子来注意,这样您就不会 运行 在重新渲染时发生不必要的状态更改。
我将包含对代码相关位的更改(在 App 组件的 return 语句之前)
const [email, setEmail] = React.useState('');
const [password, setPassword] = React.useState('');
const {login, error} = React.useContext(AuthContext);
const [errorForwarded, setErrorForwarded] = React.useState(null);
React.useEffect(() => {
if (error) {
setErrorForwarded(error);
}
}, [error]) //using an array of dependencies like this ensures that the function only runs on changes in the error state
React.useEffect(() => {
if (!email || !password) {
setErrorForwarded('fields-empty');
}
}, [email, password]) //similarly, only run this hook for changes in email or password
谢谢大家,我知道导致重新渲染的问题是直接在函数组件中的多个 if 语句,我只是想不出如何克服它。
当我使用一个函数来检查那些 if 条件以设置这些状态并在调用 API 之前在按钮提交中调用该函数时,它起作用了。但我认为 useEffect hook 做得更好,谢谢大家的澄清。
我能澄清一下吗,一开始错误变量是空的,所以 errorForwarded 将被设置为空。现在再次重新渲染时,errorForwarded 将被设置为空。所以我的问题是,即使检测到状态变化,实际状态值也没有改变。那为什么要重新渲染发生。谢谢。
我正在使用 React context 获取 context provider 文件中定义的登录函数和错误以登录到 firebase 数据库,并使用登录时抛出的错误在应用程序中显示它。
我的问题是,当我只是使用从 firebase 身份验证抛出的错误来显示应用程序中的错误时,我没有收到任何错误,但我还添加了其他错误,如空字段,以在中显示错误字段应用程序。
这样做之后我得到了太多重新渲染的错误。我认为这个错误是由于在函数中使用了多个 if 语句。你能建议一个新的选项吗?如果这是错误的,请解释一下。
上下文提供程序文件
import React from 'react';
import auth from '@react-native-firebase/auth';
export const AuthContext = React.createContext();
export const AuthProvider = ({children}) => {
const [user, setUser] = React.useState(null);
const [error, setError] = React.useState('');
return (
<AuthContext.Provider
value={{
user,
setUser,
error,
login: async (email, pwd) => {
try {
await auth().signInWithEmailAndPassword(email, pwd);
} catch (e) {
setError(e);
}
},
register: async (email, pwd) => {
try {
await auth().createUserWithEmailAndPassword(email, pwd);
} catch (e) {
setError(e);
}
},
logout: async () => {
try {
await auth().signOut();
} catch (e) {
console.log(e);
}
},
}}>
{children}
</AuthContext.Provider>
);
};
应用文件
import React from 'react';
import {Button, Image, Text, TouchableOpacity, View} from 'react-native';
import styles from '../styles/Styles';
import FormInput from '../components/FormInput';
import FormButton from '../components/FormButton';
import SocialButton from '../components/SocialButton';
import {AuthContext} from '../navigation/AuthProvider';
import ErrorText from '../components/ErrorText';
const LoginScreen = ({navigation}) => {
const [email, setEmail] = React.useState('');
const [password, setPassword] = React.useState('');
const {login, error} = React.useContext(AuthContext);
const [errorForwarded, setErrorForwarded] = React.useState(null);
if (error) {
setErrorForwarded(error);
}
if (!email || !password) {
setErrorForwarded('fields-empty');
}
const renderErrorText = e => {
if (e.code === 'auth/invalid-email') {
return <ErrorText errorText="Email invalid!" />;
}
if (e.code === 'auth/user-not-found') {
return <ErrorText errorText="User not found!" />;
}
if (e.code === 'auth/wrong-password') {
return <ErrorText errorText="Wrong password!" />;
}
if (e === 'fields-empty') {
return <ErrorText errorText="Fields cannot be empty!" />;
}
};
return (
<View style={styles.loginContainer}>
<Image
source={require('../assets/rn-social-logo.png')}
style={styles.loginLogo}
/>
<Text style={styles.loginText}>Sign In</Text>
<FormInput
labelValue={email}
onChangeText={email => setEmail(email)}
placeholderText="Email"
iconType="user"
keyboardType="email-address"
autoCapitalize="none"
autoCorrect={false}
/>
<FormInput
labelValue={password}
onChangeText={pwd => setPassword(pwd)}
placeholderText="Password"
iconType="lock"
secureTextEntry={true}
/>
{error ? renderErrorText(errorForwarded) : null}
<FormButton
buttonTitle="Sign In"
onPress={() => {
{
email && password ? login(email, password) : {};
}
}}
/>
<TouchableOpacity style={styles.loginForgetBtn}>
<Text style={styles.loginNavBtnText}>Forgot Password?</Text>
</TouchableOpacity>
<SocialButton
buttonTitle="Sign In with Facebook"
buttonType="facebook-square"
color="#4867aa"
backgroundColor="#e6eaf4"
/>
<SocialButton
buttonTitle="Sign In with Google"
buttonType="google"
color="#de4d41"
backgroundColor="#f5e7ea"
/>
<TouchableOpacity
style={styles.loginForgetBtn}
onPress={() => navigation.navigate('Signup')}>
<Text style={styles.loginNavBtnText}>
Don't have an account? Create here...
</Text>
</TouchableOpacity>
</View>
);
};
export default LoginScreen;
您遇到多次重新呈现的原因与函数中的 if 条件无关。通过 运行 直接在组件函数内设置状态的函数,您将强制重新渲染,然后它开始从上到下 运行 函数,再次设置状态。
只有 React 钩子不是 reinitialized/run 并且可以在每次后续重新渲染时避免 运行ning,因此您需要使用带有依赖项数组的 useEffect()
钩子来注意,这样您就不会 运行 在重新渲染时发生不必要的状态更改。
我将包含对代码相关位的更改(在 App 组件的 return 语句之前)
const [email, setEmail] = React.useState('');
const [password, setPassword] = React.useState('');
const {login, error} = React.useContext(AuthContext);
const [errorForwarded, setErrorForwarded] = React.useState(null);
React.useEffect(() => {
if (error) {
setErrorForwarded(error);
}
}, [error]) //using an array of dependencies like this ensures that the function only runs on changes in the error state
React.useEffect(() => {
if (!email || !password) {
setErrorForwarded('fields-empty');
}
}, [email, password]) //similarly, only run this hook for changes in email or password
谢谢大家,我知道导致重新渲染的问题是直接在函数组件中的多个 if 语句,我只是想不出如何克服它。
当我使用一个函数来检查那些 if 条件以设置这些状态并在调用 API 之前在按钮提交中调用该函数时,它起作用了。但我认为 useEffect hook 做得更好,谢谢大家的澄清。
我能澄清一下吗,一开始错误变量是空的,所以 errorForwarded 将被设置为空。现在再次重新渲染时,errorForwarded 将被设置为空。所以我的问题是,即使检测到状态变化,实际状态值也没有改变。那为什么要重新渲染发生。谢谢。