微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用上下文修复 React Native 应用程序中的“无法从不同组件的函数体内部更新组件”警告

如何解决使用上下文修复 React Native 应用程序中的“无法从不同组件的函数体内部更新组件”警告

我有一个简单的 RN 应用程序,到目前为止几乎只有登录功能。它使用 Apollo GraphQL 调用后端并将用户令牌和名称存储在 React Context 对象中。上下文对象具有用户和 setUser 函数(并在 App.js 中实例化)。登录屏幕在成功登录时从 UserContext 对象调用 setUser。

这一直工作正常,但今天我更新到 React 16.3 并开始收到警告:

无法从不同组件的函数体内部更新组件

并列出我在收到成功响应时调用 setUser 函数的行。

App.js 使用 useState 来跟踪用户和 setUser 函数并将其放入一个对象中以传递给 UserContext.Provider:

export default function App(props) {
  const [user,setUser] = useState(null)
  const contextVal = { user: user,setUser: setUser }

    return (
      <ApolloProvider client={client}>
        <UserContext.Provider value={contextVal}>
          <View style={styles.container}>
            {Platform.OS === 'ios' && <StatusBar barStyle="default" />}
            <AppNavigator />
          </View>
        </UserContext.Provider>
      </ApolloProvider>
    );
}

LoginScreen 从 UserContext 中检索 user 和 setUser,当它从 sigin 突变中获取 data 时,尝试将一个简单的用户对象传递给 setUser:

  const [email,setEmail] = useState('')
  const [password,setPassword] = useState('')
  const [signin,{ data,error,loading }] = useMutation(SIGNIN_MUTATION)
  const { user,setUser } = useContext(UserContext)

  useEffect(() => {
    if (user) {
      props.navigation.navigate('Main')
    }
  },[user])

  if (loading) return (
    <View style={styles.main}>
      <Text style={styles.text}>Logging you in!</Text>
      <ActivityIndicator size='large' />
    </View>
  )

  if (data) { // ERROR IS HERE
    setUser({
      token: data.signin.token,name: data.signin.user.name,})
  }

  return (
    <View style={styles.main}>
      <Text style={styles.welcome}>Welcome to Bravauto!</Text>
      <Text style={styles.error}>{error ? errorMessage(error) : ''}</Text>
      <Text>Please login to continue:</Text>
      <TextInput style={styles.input} onChangeText={(text) => setEmail(text)} placeholder="email" />
      <TextInput style={styles.input} onChangeText={(text) => setPassword(text)} placeholder="password" secureTextEntry={true} />
      <Button title="Login!" onPress={() => signin({ variables: { email: email,password: password } })} />
      <Button title="No Account? Register Here" onPress={() => props.navigation.navigate('Registration')} />
    </View>
  )

我记得要让它工作,我必须在 useEffect 调用中包装“已经有一个用户”的情况(它调用 props.navigate),我发现其他帖子建议将这段代码包装在 useEffect 中将修复警告。但是,如果我将此代码包装在像这样的 useEffect 钩子中:

  useEffect(() => {
    if (data) {
      setUser({
        token: data.signin.token,})
    }
  })

我收到错误而不是警告:

渲染的钩子比预期的少。这可能是由于意外的提前退货声明造成的。

任何帮助将不胜感激!

解决方法

您需要在 useEffect 正在使用的列表中包含数据字段:

useEffect(() => {
    if (data) {
      setUser({
        token: data.signin.token,name: data.signin.user.name,})
    }
  },[data])
,

哎呀,忘了发帖了,我最终找到了这个问题的答案。解决方案是使用 Apollo 提供的回调:

  const [signin,{ loading }] = useMutation(SIGNIN_MUTATION,{
    onCompleted: (data) => {
      setAuth(data.signin.token);
    },onError: (errorMsg) => {
      setError(errorMessage(errorMsg));
    },errorPolicy: "none"
  });

改用这种方法后一切正常。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。