【问题标题】:React , custom hook slow renderReact ,自定义钩子慢渲染
【发布时间】: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)

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

【问题讨论】:

    标签: reactjs react-native react-hooks react-navigation react-forms


    【解决方案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) 而不是分别抓取键和值。
    • 谢谢,我还在优化这段代码
    猜你喜欢
    • 2022-07-18
    • 2021-01-31
    • 2021-11-02
    • 2022-01-02
    • 2020-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多