简体   繁体   English

React-Native:无法在呈现不同组件时更新组件

[英]React-Native: cannot update a component while rendering a different component

I've got this simple component Login:我有这个简单的组件登录:

function Login() {
  const [isFormValidState, setIsFormValidState] = React.useState(false);
  const [credentialState, setCredentialState] = React.useState();

  function getFormErrors(errors: any, dirty: boolean) {
    setIsFormValidState(!Object.keys(errors).length && dirty);
  }

  function getFormValues(values: any) {
    setCredentialState(values);
  }

  function doAction() {
    //credentialState rest call...
  }

  return (
    <View>
      <Text>Login</Text>
      <UserCredentialForm getFormValues={getFormValues} getFormErrors={getFormErrors}/>
      <Button title='Entra' disabled={!isFormValidState} onPress={doAction}/>
    </View>
  );
}

Which calls UserCredentialForm:其中调用 UserCredentialForm:

export default function UserCredentialForm({ getFormValues, getFormErrors }) {
[...]
  return (
    <Formik innerRef={formRef} validationSchema={formSchema} initialValues={state.form} onSubmit={() => { }}>
      {({ handleChange, values, touched, errors, dirty }) => {
        getFormValues(values);
        getFormErrors(errors, dirty);
        return <React.Fragment>
          // <TextInput/>....              
        </React.Fragment>
      }}
    </Formik>
  );

[...]
}

While navigating in my app I've got this error:在我的应用程序中导航时出现此错误:

react native cannot update a component Login while rendering a different component Formik. react native 无法在呈现不同组件 Formik 时更新组件登录。

Then it points me to the error in the setCredentialState inside getFormValues handler in Login component.然后它指出了登录组件中getFormValues处理程序中setCredentialState中的错误。 I've resolved this using a ref instead of a state, but the problem itself is unsolved to me.我已经使用 ref 而不是 state 解决了这个问题,但问题本身对我来说还没有解决。

What if I need to update my parent component view after a child event?如果我需要在子事件后更新我的父组件视图怎么办?

The reason for that error is because you call setState inside render() .该错误的原因是因为您在render()中调用了setState The call getFormValues(values) , which set the state of credentialState is called inside the render.设置credentialState的 state 的调用getFormValues(values)在渲染内部调用。

When the state is set, the Login component get rerendered, thus recreating a new function of getFormValues .设置 state 后,将重新呈现Login组件,从而重新创建一个新的 function 的getFormValues As this is used as the prop of UserCredentialForm , it also causes that component to rerender, which causes the render prop inside Formik to calls again, which calls getFormValues causing the state change, causing an infinite loop.由于它被用作UserCredentialForm的 prop,它还会导致该组件重新渲染,这会导致Formik中的 render prop 再次调用,调用getFormValues导致 state 更改,从而导致无限循环。

One solution you can try is to add useCallback to the two functions, which prevent them to have new identities after the state changes and consequently change the props, thus creating infinite rerender.您可以尝试的一种解决方案是将useCallback添加到这两个函数,这可以防止它们在 state 更改后具有新身份并因此更改道具,从而创建无限重新渲染。

function Login() {
  const [isFormValidState, setIsFormValidState] = React.useState(false);
  const [credentialState, setCredentialState] = React.useState();

  const getFormErrors = useCallback(function getFormErrors(errors: any, dirty: boolean) {
    setIsFormValidState(!Object.keys(errors).length && dirty);
  }, []);

  const getFormValues = useCallback(function getFormValues(values: any) {
    setCredentialState(values);
  }, []);

  function doAction() {
    //credentialState rest call...
  }

  return (
    <View>
      <Text>Login</Text>
      <UserCredentialForm getFormValues={getFormValues} getFormErrors={getFormErrors}/>
      <Button title='Entra' disabled={!isFormValidState} onPress={doAction}/>
    </View>
  );
}

However, there is still an issue and that is the identity of values may not be stable and by setting it to state, it will keep causing rerender.但是,仍然存在一个问题,即values的标识可能不稳定,将其设置为 state 会导致重新渲染。 What you want to do is to tell UserCredentialForm not to rerender even when that state changes, and since the state is not used as a prop in UserCredentialForm , you can do that with React.memo .你想要做的是告诉UserCredentialForm即使 state 发生变化也不要重新呈现,并且由于 state 没有用作UserCredentialForm中的道具,你可以使用React.memo来做到这一点。


export default React.memo(function UserCredentialForm({ getFormValues, getFormErrors }) {
[...]
  return (
    <Formik innerRef={formRef} validationSchema={formSchema} initialValues={state.form} onSubmit={() => { }}>
      {({ handleChange, values, touched, errors, dirty }) => {
        getFormValues(values);
        getFormErrors(errors, dirty);
        return <React.Fragment>
          // <TextInput/>....              
        </React.Fragment>
      }}
    </Formik>
  );

[...]
})

I think you got an unlimited loop of rendering,我想你有一个无限循环的渲染,

you setState by getFormValues and the Login component re-render make UserCredentialForm re-render too, so it call getFormValues again and again您通过 getFormValues 设置状态并且登录组件重新呈现也使 UserCredentialForm 重新呈现,因此它一次又一次地调用 getFormValues

You can call getFormValues(values) in a useEffect hook after values of formik update您可以在 formik 更新值后在 useEffect 挂钩中调用 getFormValues(values)

You are calling getFormValues and getFormErrors inside a callback provided by Formik, that means you cannot wrap them inside an effect hook to suppress this warning or it will violate rules of hooks .您在 Formik 提供的回调中调用getFormValuesgetFormErrors ,这意味着您不能将它们包装在效果钩子中以抑制此警告,否则它将违反hooks 规则

I faced the same issue in React JS and got rid of it by using the following: approach.我在 React JS 中遇到了同样的问题,并通过使用以下方法摆脱了它:方法。

I used useFormik hook as an alternate.我使用useFormik钩子作为替代。

and afterwards I refactored Formik form into a new component from where I made state changes to parent component.然后我将 Formik 表单重构为一个新组件,从那里我对父组件进行了 state 更改。 This way I neither violated rules of hooks nor got this warning.这样我既没有违反钩子规则也没有得到这个警告。

Also in the that newly refactored component you might need useFormikContext and useField同样在新重构的组件中,您可能需要useFormikContextuseField

Simple example can be like简单的例子可以像

UserCredentialForm:用户凭证表格:

 // Formik x React Native example
 import React from 'react';
 import { Button, TextInput, View } from 'react-native';
 import { Formik } from 'formik';
 
 export const MyReactNativeForm = ({onSubmit}) => (
   <Formik
     initialValues={{ email: '' }}
     onSubmit={values => onSubmit(values)}
   >
     {({ handleChange, handleBlur, handleSubmit, values }) => (
       <View>
         <TextInput
           onChangeText={handleChange('email')}
           onBlur={handleBlur('email')}
           value={values.email}
         />
         <Button onPress={handleSubmit} title="Submit" />
       </View>
     )}
   </Formik>
 );

Usage like用法像

function Login() {

  function doAction(values) {
    console.log(values);
    //credentialState rest call...
  }

  return (
    <View>
      ....
      <UserCredentialForm onSubmit={doAction} />
      ....
    </View>
  );
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 组件未在 react-native 中呈现 - Component not rendering in react-native React - 超过最大更新深度/在渲染不同组件时无法更新组件 - React - Maximum update depth exceeded / Cannot update a component while rendering a different component React-Bootstrap 模式未关闭。 错误:渲染不同组件时无法更新组件 (`OnboardPage`) - React-Bootstrap modal not closing. Error: Cannot update a component (`OnboardPage`) while rendering a different component 在反应项目上出现“在呈现不同组件时无法更新组件(`BrowserRouter`)”错误 - getting "Cannot update a component (`BrowserRouter`) while rendering a different component" error on react project 警告:渲染不同组件时无法更新组件。 ReactJS - Warning: Cannot update a component while rendering a different component. ReactJS 警告:在渲染不同的组件(`FormSocialIcon`)时无法更新组件(`BrowserRouter`) - Warning: Cannot update a component (`BrowserRouter`) while rendering a different component (`FormSocialIcon`) 渲染不同组件时无法更新组件(`App`) - Cannot update a component (`App`) while rendering a different component 警告:在渲染不同的组件(`History`)时无法更新组件(`App`) - Warning: Cannot update a component (`App`) while rendering a different component (`History`) 在呈现不同的组件 (`CellRenderer`) 时无法更新组件 (`Categoriess`) - Cannot update a component (`Categoriess`) while rendering a different component (`CellRenderer`) 呈现不同组件警告时无法更新组件 - Cannot update a component while rendering a different component warning
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM