I have two reusable
TextInputs, namely, AppTextInput
and a reusable button, namely, AppButton
.
Here are their codes:
AppButton.js
const AppButton = ({
title = '',
iconName = '',
onPress,
mode = 'contained',
...props
}) => {
console.log("Button rendered")
return (
<Button
icon={iconName}
mode={mode}
onPress={onPress}
{...props}
>
{title}
</Button>
)
}
Here is for the AppTextInput.js
const AppTextInput = ({
inputStyle,
outlineStyle,
leftIcon = '',
rightIcon = '',
right,
onRightIconPress,
label = '',
...props
}) => {
console.log([label, " TextInput Rendered"])
return (
<TextInput
label={label}
mode='outlined'
style={[styles.inputStyle, inputStyle]}
outlineStyle={[styles.outlineStyle, outlineStyle]}
left={
leftIcon ? (
<TextInput.Icon
icon={leftIcon}
disabled
/>
) : null
}
right={
rightIcon ? (
<TextInput.Icon
icon={rightIcon}
onPress={onRightIconPress}
/>
) : (
right
)
}
{...props}
/>
)
}
I added console.log()
s on the two to determine if they re-renders or not.
Now here’s my problem:
I have a simple form that consists of fields of CurrentPassword
and NewPassword
.
Whenever I change the state for the icon
of the CurrentPassword
field, it also renders the AppButton
and the NewPassword
TextInput.
How do I prevent the re-render?
Below is sample image and code for the parent component:
ChangePasswordScreen.js
const ChangePasswordScreen = () => {
const [currentPasswordSecureText, setCurrentPasswordSecureText] = useState(true);
const [newPasswordSecureText, setNewPasswordSecureText] = useState(true);
const [currentPasswordIcon, setCurrentPasswordIcon] = useState("eye-off-outline");
const [newPasswordIcon, setNewPasswordIcon] = useState("eye-off-outline");
const showHideCurrentPassword = () => {
setCurrentPasswordSecureText(!currentPasswordSecureText)
currentPasswordIcon === "eye-off-outline" ?
setCurrentPasswordIcon("eye") :
setCurrentPasswordIcon("eye-off-outline");
}
const showHideNewPassword = () => {
setNewPasswordSecureText(!newPasswordSecureText)
newPasswordIcon === "eye-off-outline" ?
setNewPasswordIcon("eye") :
setNewPasswordIcon("eye-off-outline");
}
return (
<ScrollView
style={styles.container}
keyboardShouldPersistTaps='handled'
>
<AppTextInput
label='Current Password'
autoCapitalize="none"
autoCorrect={false}
inputStyle={styles.input}
leftIcon='lock'
rightIcon={currentPasswordIcon}
secureTextEntry={currentPasswordSecureText}
onRightIconPress={showHideCurrentPassword}
/>
<AppTextInput
label='New Password'
autoCapitalize="none"
autoCorrect={false}
inputStyle={styles.input}
leftIcon='lock'
rightIcon={newPasswordIcon}
secureTextEntry={newPasswordSecureText}
onRightIconPress={showHideNewPassword}
/>
<AppButton
title="Update"
style={styles.button}
/>
</ScrollView>
)
}
This is the result of the log whenever I press the eye icon
.
I have tried useCallback
and useMemo
but I don’t quite get it as I am still unfamiliar with the two.
Thank you!
3
Answers
Maybe this will solve your problem. Replace your useState with useRef for input.
Please let me know if this works.
That’s very common issue in react development.
I have faced same issues earlier So, I tried below solution.
Example:
Although you can run a line of code that shows you
button rendering...
, there’s a React core functionality calledthe reconciliation algorithm
. This part works at low level DOM manipulation and it’s responsible for determining what DOM nodes are being rendered / updated. Basically it’s a diff check between Virtual DOM and Real DOM.EDIT:
As an addition to my previous comment where I try to explain in a very simple way how React works, I would say: Every change of state will trigger re-rendering. But React provide us some options to work around this issue. One of them is working with
useRef
hook.