React ,自定义钩子慢渲染
Posted
技术标签:
【中文标题】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)
而不是分别抓取键和值。
谢谢,我还在优化这段代码以上是关于React ,自定义钩子慢渲染的主要内容,如果未能解决你的问题,请参考以下文章
为啥 jest 不能为我正在测试的自定义 React 钩子提供 useTranslation 钩子?