React ,自定义钩子慢渲染

     2023-02-16     156

关键词:

【中文标题】React ,自定义钩子慢渲染【英文标题】:React , custom hook slow render 【发布时间】:2022-01-10 17:15:29 【问题描述】:

您好,我制作了一个自定义钩子,它与通用表单的组件一起使用,但是,我注意到状态更改时它很慢。

#customHook
export const useFormController = (meta) => 
  const  setVisible, setLoading  = useContext(FeedBackContext);
  const itemsRef = useRef([]);
  const 
    control,
    setValue,
    handleSubmit,
    formState:  errors ,
   = useForm<Partial<any>>(
    mode: "onBlur",
    shouldUnregister: true,
    resolver: yupResolver(meta.validation),
  );

  const onRef = function (input) 
    this.itemsRef.current[this.index] = input;
  ;

  const onSubmit = (data: any) => 
    if(meta.onSubmit)
      meta.onSubmit(data);
    else
      setVisible(true);
      setLoading(true);
      meta.service.submit(data);
    
  ;

  const isJsonEmpty = (val = ) => 
    return Object.keys(val).length == 0;
  ;
  const onSubmitIditing = function () 
    let index = ++this.index;
    if (isJsonEmpty(errors) && this.end) 
      handleSubmit(onSubmit)();
     else if (!this.end) 
      this.itemsRef.current[index]._root.focus();
    
  ;
  const setFields = (json) => 
    const items = Object.keys(json);
    const values = Object.values(json)
    console.log('Cambiando fields en formControllser...', json)
    for (let i = 0; i < items.length; i++) 
      //console.log('Cambiando valores...', items[i], values[i])

      setValue(items[i], values[i],  shouldValidate: true )
    
  


  const getItems = () => 
    console.log('Meta namess', meta.names, meta);

    if (!meta && !meta.names) return [];

    return meta.names.map(function (item, index) 
      const isEnd =
        meta.options && meta.options[item] && meta.options[item].end
          ? true
          : false;

      const isSecure =
        meta.options && meta.options[item] && meta.options[item].secure
          ? true
          : false;

      const label = meta.alias ? meta.alias[item] : item;
      const visible = meta.invisibles ? (meta.invisibles[item] ? false : true) : true;
      const def = meta.defaults ? meta.defaults[item] : "";

      const disabled = (val) => 
        const b = meta.disableds ? (meta.disableds[item] ? true : false) : false;
        return b;
      

      return 
        name: item,
        label: label,
        disabled: disabled,
        onRef: onRef.bind( itemsRef: itemsRef, index: index ),
        onSubmitEditing: onSubmitIditing.bind(
          itemsRef: itemsRef,
          index: index,
          end: isEnd,
          errors: errors,
        ),
        visible: visible,
        setFields,
        defaultValue: def,
        errors: errors,
        secureTextEntry: isSecure,
        styles: styles,
        control: control,
        options: meta.options[item] ? meta.options[item] : null,
      ;
    );
  

  const getData = useMemo(() => 
    console.log('Get data calback v2', meta);
    return 
      handleSubmit,
      items: getItems(),
      onSubmit,
      errors,
      setFields
    ;
  , [meta])


  return getData;
;




export const Client: React.FC<any> = React.memo(( navigation, route ) => 


  const 
    alias,
    defaults,
    ubigeoSeleccionado,
    setUbigeoSeleccionado,
    editable,
    inputLabel,
    search,
    getDisabled,
    getInvisibles,
    getAlias,
    getDefaults,
    disableds,
    invisibles,
    searchVisible,
    idTypeDocument,
    currentTypeDocument,
    allTypeDocuments,
    onValueChange,
    onChangeText  = useContext(CreateClientContext);
  const [mode, setMode] = useState(() => 
    return route?.params?.mode;
  )
  const [client, setClient] = useState(() => 
    return route?.params?.client;
  )
  const  dispatchClient  = useContext(GlobalContext);
  const clientService = useClientService();
  const ref = useRef(0);
  const options = useMemo(() => 

    return 
      names: ["ane_numdoc", "ane_razsoc", "ane_alias", "ane_email", "ane_tel", "ane_tel2", "ane_dir"],
      validation: clientValidation,
        alias: alias,
        defaults: defaults,
        disableds: disableds,
        service: 
          submit: (data) => 
            const parse =  ...data, ubigeo_id: ubigeoSeleccionado.ubi_id, ane_tipo_cp: 2, ane_tipdoc: currentTypeDocument.id 
            if (mode == "update") 
              //console.log('Actualizando...', client.id, parse);
              clientService.updateById(client.id, parse)
                .then(ok => 
                  Alert.alert('Actualizaciòn de cliente', "Cliente Actualizado")
                  dispatchClient(
                    type: 'create',
                    payload: ok
                  );

                  setTimeout(() => 
                    navigation.navigate('App', 
                      screen: "Clients"
                    )
                  , 500)

                ).catch(e => 
                  Alert.alert('Actualizaciòn de cliente', "No se pudo actualizar")
                )

             else 
              clientService.create(parse)
                .then(ok => 
                  dispatchClient(
                    type: 'create',
                    payload: ok
                  );
                  Alert.alert('Cliente', "Cliente creado")

                  setTimeout(() => 
                    navigation.navigate('App', 
                      screen: "Clients"
                    )
                  , 500)
                )
                .catch(e => 
                  (e);
                  Alert.alert('Error', "No se pudo crear el cliente")
                )
            
          
        ,
        invisibles: invisibles,
        options: 
          ane_dir: 
            end: true
          ,
        
    

  , [getDisabled,
    getInvisibles,
    getAlias,
    getDefaults])
  const  items, handleSubmit, onSubmit, errors, setFields  = useFormController(options);

  useEffect(() => 
    ref.current++;
  )

  useEffect(() => 
    if (route.params) 
      console.log('Ref current', ref.current);
      setMode(route.params.mode);
      setClient(route.params.client);
    
  , [route.params])
  useEffect(() => 
    // console.log('Mode', mode, client.id);
    if (mode == "update" && client) 
      console.log('cambiando fields'), ref;
      setFields(client)
    
  , [mode, client])

  // useEffect(()=>

  // ,[instanceDocument])

  useEffect(() => 
    console.log('Cambiando cliente...', mode, client);
    console.log(ref.current);
  , [client])

  useEffect(() => 
    //Creación
    console.log('set defaults..', ref.current);
    if (Object.keys(defaults).length > 0) 
      setFields(defaults)
    
  , [getDefaults])
  console.log('Current', ref.current);
  return (
    <StyleProvider style=getTheme(material)>
      <Container style= backgroundColor: "#FAF9FE" >
        <Content style=GlobalStyles.mainContainer>
          <Text style=GlobalStyles.subTitle>Cliente</Text>
          <PickerSearch
          search=search
          editable=editable
          style=styles
            searchVisible=searchVisible
          placeholder=inputLabel
          pickerItems=allTypeDocuments
          onValueChange=onValueChange
            selectedValue=idTypeDocument
          onChangeText=onChangeText
          ></PickerSearch>

          <FormListController
              // top=<Top />
              items=items
              style=GlobalStyles
            ></FormListController>

          <Bottom
            ubigeoSeleccionado=ubigeoSeleccionado
        setUbigeoSeleccionado=setUbigeoSeleccionado
        onSubmit=handleSubmit(onSubmit)
        />



        </Content>
        <AppFooter2 navigation=navigation />
      </Container>
    </StyleProvider>
  );
);

export const FormListController: React.FC<any> = React.memo(( children, items = [], style, top = null, bottom = null ) => 

  console.log('%c Form list controlllser...', "background-color:#ccc");
  console.log('items', items)
  return (
    <>
      <Form style=!!style.form ? style.form : style.formContainer>
        top
        items.map((item: any, index) => 

          return <FormItemController ...item key=index />;

        )
        
        bottom

      </Form>
    </>
  );
);


export const FormItemController: React.FC<any> = React.memo((props: any) => 
  console.log('Form item controller print', props)
  if (props.visible) 
    return (
      <>
        <Controller
          control=props.control
          render=
            ( field:  onChange, onBlur, value  ) => 

              return (
                <Item regular style=props.styles.item>
                  <Label style=props.styles.label>props.label</Label>
                  <Input
                    onBlur=onBlur
                    disabled=props.disabled(value)
                    onChangeText=(value) => onChange(value)
                    secureTextEntry=props.secureTextEntry
                    onSubmitEditing=props.onSubmitEditing
                    value=value
                    ref=props.onRef
                  />
                </Item>
              )
            

          

          defaultValue=props.defaultValue
          name=props.name
        />
        props.errors && props.errors[props.name] && (
          <TextError value=props.errors[props.name].message />
        )
        /* props.options && props.options.errorEmpty && props.errors[""] && (
          <TextError value=props.errors[""].message />
        ) */
      </>
    );
  
  else 
    return <></>
  
);

我使用相同的组件来创建和编辑客户端,但是在编辑和查看 FormItemController 时,日志时间跨度小于 1 秒,但是直到 8 或 10 秒后才会呈现。

这是我的日志输出。

Update cliente...  500ms 

set defaults.. 77
Client num render 77
Client num render 78
Client num render 79
Client num render 80
Client num render 81
Client num render 82
Client num render 83
Client num render 84
Client num render 85
Client num render 86
Client num render 87
Client num render 88
Client num render 89
Client num render 90
Client num render 91
Client num render 92
Client num render 93
Client num render 94
Client num render 95
Client num render 96
Client num render 97
Client num render 98
Client num render 99
Client num render 100  (6-8 seg)

我遇到的问题是我编辑的时候,我用表格创建的时候没有问题,我没有找到瓶颈来改进和防止它变慢。

【问题讨论】:

【参考方案1】:

在尝试了几个选项后,我意识到在传递 setValue 时,我发送了几个空值和不符合表单的对象,过滤了这些数据,使最终渲染通过时间从 8 秒缩短到不到 1 秒

  const setFields = (json) => 
    const items = Object.keys(json);
    const values = Object.values(json)
    for (let i = 0; i < items.length; i++) 
      if (!!values[i] && typeof values[i] != 'object') 
        setValue(items[i], values[i])
      

    
  

【讨论】:

只是一个小的可能的代码改进:迭代 Object.entries(json) 而不是分别抓取键和值。 谢谢,我还在优化这段代码

用 Jest 模拟 React 自定义钩子

】用Jest模拟React自定义钩子【英文标题】:MockingReactcustomhookwithJest【发布时间】:2021-03-2323:38:28【问题描述】:在对React组件进行单元测试时,我需要模拟我的自定义钩子。我已经阅读了一些关于这个简单任务的教程和***答案,... 查看详情

如何使用自定义钩子和 useContext 仅渲染相关组件

】如何使用自定义钩子和useContext仅渲染相关组件【英文标题】:HowtorenderonlytheconcernedcomponentwithacustomhookanduseContext【发布时间】:2021-09-1208:04:37【问题描述】:我正在尝试基于useContext创建一个自定义钩子useFocus,以便仅将焦点设... 查看详情

React Jest 测试:模拟这个自定义 React 钩子

】ReactJest测试:模拟这个自定义React钩子【英文标题】:ReactJestTesting:MockthisCustomReacthook【发布时间】:2021-04-1715:19:55【问题描述】:我正在使用它在React应用程序(基于钩子)而不是redux中存储状态。importReact,createContext,useContext,u... 查看详情

如何在 React 中编写 useComponent 自定义钩子?

】如何在React中编写useComponent自定义钩子?【英文标题】:HowtowriteauseComponentcustomhookinReact?【发布时间】:2021-12-3020:52:04【问题描述】:我想创建一个自定义钩子useComponent,它返回一个JSX.Element,它将在其他地方呈现。我试过这个... 查看详情

用于获取数据的自定义 React 钩子无法正常工作

】用于获取数据的自定义React钩子无法正常工作【英文标题】:CustomReacthookforfetchingdataisnotworkingcorrect【发布时间】:2022-01-0118:08:19【问题描述】:我有这个用于从API获取数据的自定义React钩子:importuseState,useEffectfrom\'react\';constAPI... 查看详情

为啥 jest 不能为我正在测试的自定义 React 钩子提供 useTranslation 钩子?

】为啥jest不能为我正在测试的自定义React钩子提供useTranslation钩子?【英文标题】:WhyisjestnotabletoprovidetheuseTranslationhooktoacustomReacthookI\'mtesting?为什么jest不能为我正在测试的自定义React钩子提供useTranslation钩子?【发布时间】:2021... 查看详情

在 React 自定义钩子中正确输入 useRef 值

】在React自定义钩子中正确输入useRef值【英文标题】:ProperlytypinguseRefvaluesinaReactcustomhook【发布时间】:2021-06-2920:45:51【问题描述】:我有一个自定义钩子,它在我的TS应用程序中返回值useRef。不幸的是,它抱怨我返回的ref的类型... 查看详情

自定义 React `useFetch` 钩子 - 我需要维护多个状态吗?

】自定义React`useFetch`钩子-我需要维护多个状态吗?【英文标题】:CustomReact`useFetch`hook-doIneedtomaintainmultiplestates?【发布时间】:2019-04-2206:06:34【问题描述】:我已经实现了一个自定义的useFetch钩子,所以请围绕我的应用进行抓取... 查看详情

React - nextjs 在 useEffect 中调用自定义钩子

】React-nextjs在useEffect中调用自定义钩子【英文标题】:React-nextjsCallingcustomhookinuseEffect【发布时间】:2021-09-1012:35:22【问题描述】:我正在尝试调用使用useEffect和useSWR的“useUser”自定义挂钩;_app.tsx的内部useEffect。但它会抛出,In... 查看详情

尽管状态发生了变化,但自定义钩子不会触发组件重新渲染

】尽管状态发生了变化,但自定义钩子不会触发组件重新渲染【英文标题】:Customhooknottriggeringcomponentrerenderdespitechangesinstate【发布时间】:2020-12-0206:48:38【问题描述】:上下文:我有一个自定义挂钩来获取Firestore文档。它监视... 查看详情

如何使用 JEST、Enzyme 在 React 中测试自定义钩子?

】如何使用JEST、Enzyme在React中测试自定义钩子?【英文标题】:HowtotestcustomhooksinReactusingJEST,Enzyme?【发布时间】:2021-03-1009:07:30【问题描述】:我有一个像下面这样的自定义钩子constuseSum=(a=1,b=1)=>const[sum,setSum]=useState(a+b);useEffect... 查看详情

如何使用自定义 React 钩子通过 Axios 发出 POST 或 DELETE 请求

】如何使用自定义React钩子通过Axios发出POST或DELETE请求【英文标题】:HowtouseacustomReacthooktomakeaPOSTorDELETErequestwithAxios【发布时间】:2022-01-2208:50:19【问题描述】:我正在尝试在React中创建一个通用的useAxios钩子。我希望能够将此钩... 查看详情

为啥我不能将其转换为自定义的 React 钩子?

】为啥我不能将其转换为自定义的React钩子?【英文标题】:Whycan\'tIconvertthistoacustomReacthook?为什么我不能将其转换为自定义的React钩子?【发布时间】:2022-01-2210:58:40【问题描述】:我的React应用程序中有一个薄的“服务层”,... 查看详情

如何将 React 组件的自定义钩子与“map”一起使用

】如何将React组件的自定义钩子与“map”一起使用【英文标题】:HowtouseReactcomponent\'scustomhookwith"map"【发布时间】:2021-04-0721:51:04【问题描述】:我正在尝试制作一个Checkbox组件。这是我的Checkbox.tsx。importReactfrom"react";import... 查看详情

React 用 useReducer 替换 useState,同时还使用自定义钩子

】React用useReducer替换useState,同时还使用自定义钩子【英文标题】:ReactreplacinguseStatewithuseReducerwhilealsousingacustomhook【发布时间】:2021-05-1004:07:59【问题描述】:所以我正在制作一个预算跟踪应用程序,用户可以在其中将收入来源... 查看详情

在 React 中,如何在所有组件中拥有一个自定义钩子实例?

】在React中,如何在所有组件中拥有一个自定义钩子实例?【英文标题】:InReact,howtohaveasingleinstanceofacustomhookinallcomponents?【发布时间】:2021-04-0223:19:27【问题描述】:我有几个组件需要访问相同的玩家列表。这个球员名单不会改... 查看详情

React Hooks:确保 useEffect 仅在自定义钩子的数组参数内容更改时运行的惯用方法

】ReactHooks:确保useEffect仅在自定义钩子的数组参数内容更改时运行的惯用方法【英文标题】:ReactHooks:IdiomaticwaytoensurethatuseEffectrunsonlywhenthecontentsofanarrayargumenttothecustomhookchange【发布时间】:2019-12-0506:15:04【问题描述】:我在React... 查看详情

如何使用 react-hooks-testing-library 测试自定义 async/await 钩子

】如何使用react-hooks-testing-library测试自定义async/await钩子【英文标题】:Howtotestcustomasync/awaithookwithreact-hooks-testing-library【发布时间】:2019-12-2101:51:45【问题描述】:我创建了一个自定义反应钩子,它应该处理所有不太重要的api请... 查看详情