I am using react native 0.68.5
When I call the renderReusableTextInput
method in Main.js
I am sending all the styles including the needed and unneeded styles. This can lead performance penalty.
So, is there a way that I can send the only needed styles to the renderReusableTextInput
method.
I also want to know is the code reusing approach of mine correct or there are better ways.
I have the following code-logic structure:
(i) A Reusable component; It has only structure no style or state
(ii) A file that includes reusable methods
(iii) The Main component, which contains components, styles and states
ReusableTextInput.js
// import ...
const ReusableTextInput = forwardRef(({
inputName,
inputLabel,
inputValue,
secureTextEntry,
textInputContainerWarperStyle,
textInputContainerStyle,
textInputLabelStyle,
textInputStyle,
textInputHelperStyle,
textInputErrorStyle,
helperText,
inputError,
onFocus,
onChangeText,
onBlur,
}, inputRef) => {
return (
<View style={[textInputContainerWarperStyle]}>
<View style={[textInputContainerStyle]}>
<Text style={[textInputLabelStyle]}>
{inputLabel}
</Text>
<TextInput
ref={(elm) => inputRef[inputName] = elm}
style={[textInputStyle]}
value={inputValue}
secureTextEntry={secureTextEntry}
onChangeText={onChangeText}
onFocus={onFocus}
onBlur={onBlur}
/>
</View>
{
((inputRef[inputName]) && (inputRef[inputName].isFocused()) && (!inputValue))
?
<Text style={[textInputHelperStyle]}>
{helperText}
</Text>
:
null
}
{
((inputError) && (inputValue))
?
<Text style={[textInputErrorStyle]}>
{inputError}
</Text>
:
null
}
</View>
);
});
export default memo(ReusableTextInput);
reusableMethods.js
// import ...
const handleFocus = (state, setState, styles) => {
const stateData = { ...state };
stateData.styleNames.textInputContainer = {
...styles.textInputContainer,
...styles[`${stateData.name}ExtraTextInputContainer`],
...styles.textInputContainerFocus,
};
stateData.styleNames.textInputLabel = {
...styles.textInputLabel,
...styles[`${stateData.name}ExtraTextInputLabel`],
...styles.textInputLabelFocus,
};
stateData.styleNames.textInput = {
...styles.textInput,
...styles[`${stateData.name}ExtraTextInput`],
...styles.textInputFocus,
};
// other logics...
setState(stateData);
};
const handleChangeText = (state, setState, text) => {
const stateData = { ...state };
// individual validation
const schemaData = Joi.object().keys(stateData.validationObj); // I used Joi for validation
const inputData = { [stateData.name]: text };
const options = { abortEarly: false, errors: { label: false } };
const result = schemaData.validate(inputData, options);
// -----
stateData.error = (result.error) ? result.error.details[0].message : '';
stateData.value = text;
// other logics...
setState(stateData);
};
const handleBlur = (state, setState, styles) => {
const stateData = { ...state };
if (stateData.value) {
stateData.styleNames.textInputContainer = {
...styles.textInputContainer,
...styles[`${stateData.name}ExtraTextInputContainer`],
...styles.textInputContainerFocus,
...styles[`${stateData.name}ExtraTextInputContainerFocus`],
...styles.textInputContainerBlurText,
...styles[`${stateData.name}ExtraTextInputContainerBlurText`],
};
stateData.styleNames.textInputLabel = {
...styles.textInputLabel,
...styles[`${stateData.name}ExtraTextInputLabel`],
...styles.textInputLabelFocus,
...styles[`${stateData.name}ExtraTextInputLabelFocus`],
...styles.textInputLabelBlurText,
...styles[`${stateData.name}ExtraTextInputLabelBlurText`],
};
stateData.styleNames.textInput = {
...styles.textInput,
...styles[`${stateData.name}ExtraTextInput`],
...styles.textInputFocus,
...styles[`${stateData.name}ExtraTextInputFocus`],
...styles.textInputBlurText,
...styles[`${stateData.name}ExtraTextInputBlurText`],
};
}
else {
stateData.styleNames.textInputContainer = { ...styles.textInputContainer, ...styles[`${stateData.name}ExtraTextInputContainer`] };
stateData.styleNames.textInputLabel = { ...styles.textInputLabel, ...styles[`${stateData.name}ExtraTextInputLabel`] };
stateData.styleNames.textInput = { ...styles.textInput, ...styles[`${stateData.name}ExtraTextInput`] };
}
// other logics...
setState(stateData);
};
// other methods...
export const renderReusableTextInput = (
state,
setState,
inputRef,
styles,
// contains all the styles from Main component and here I am sending all the styles including the needed and unneeded styles. I want improvement here
) => {
return (
<ReusableTextInput
inputName={state.name}
inputLabel={state.label}
inputValue={state.value}
inputRef={inputRef}
secureTextEntry={state.secureTextEntry}
textInputContainerWarperStyle={{...styles.textInputContainerWarper, ...styles[`${state.name}ExtraTextInputContainerWarper`]}}
textInputContainerStyle={state.styleNames.textInputContainer}
textInputLabelStyle={state.styleNames.textInputLabel}
textInputStyle={state.styleNames.textInput}
textInputHelperStyle={{...styles.textInputHelper, ...styles[`${state.name}ExtraTextInputHelper`]}}
textInputErrorStyle={{...styles.textInputError, ...styles[`${state.name}ExtraTextInputError`]}}
helperText={state.helperText}
inputError={state.error}
onFocus={() => handleFocus(state, setState, styles)}
onChangeText={(text) => handleChangeText(state, setState, text)}
onBlur={() => handleBlur(state, setState, styles)}
/>
);
};
Main.js
// import Joi from 'joi';
// import { joiPasswordExtendCore } from 'joi-password';
// import { renderReusableTextInput } from ''; ...
const schema =
{
email: Joi.string().strict()
.case("lower")
.min(5)
.max(30)
.email({ minDomainSegments: 2, tlds: { allow: ["com", "net", "org"] } })
.required(),
countryCode: // Joi.string()...,
phoneNumber: // Joi.string()...,
password: // Joi.string()...,
// ...
};
const Main = () => {
const { width: windowWidth, height: windowHeight, scale, fontScale } = useWindowDimensions();
const minimumWidth = (windowWidth <= windowHeight) ? windowWidth : windowHeight;
const styles = useMemo(() => currentStyles(minimumWidth), [minimumWidth]);
const [email, setEmail] = useState({
name: 'email', // unchangeable
label: 'Email', // unchangeable
value: '',
error: '',
validationObj: { email: schema.email }, // unchangeable
trailingIcons: [require('../../file/image/clear_trailing_icon.png')], // unchangeable
helperText: 'only .com, .net and .org allowed', // unchangeable
styleNames: {
textInputContainer: { ...styles.textInputContainer, ...styles.emailExtraTextInputContainer },
textInputLabel: { ...styles.textInputLabel, ...styles.emailExtraTextInputLabel },
textInput: { ...styles.textInput, ...styles.emailExtraTextInput },
},
});
const [phoneNumber, setPhoneNumber] = useState({
// ...
});
const [countryCode, setCountryCode] = useState({
});
const [password, setPassword] = useState({
});
// ...
const references = useRef({});
return (
<View style={[styles.mainContainer]}>
{
useMemo(() => renderReusableTextInput(email, setEmail, references.current, styles), [email, minimumWidth])
}
</View>
);
}
export default memo(Main);
const styles__575 = StyleSheet.create({
// 320 to 575
mainContainer: {
},
textInputContainerWarper: {
},
emailExtraTextInputContainerWarper: {
},
countryCodeExtraTextInputContainerWarper: {
},
phoneNumberExtraTextInputContainerWarper: {
},
passwordExtraTextInputContainerWarper: {
},
textInputContainer: {
},
emailExtraTextInputContainer: {
},
textInputContainerFocus: {
},
textInputContainerBlurText: {
},
textInputLabel: {
},
emailExtraTextInputLabel: {
},
textInputLabelFocus: {
},
textInputLabelBlurText: {
},
textInput: {
},
emailExtraTextInput: {
},
textInputFocus: {
},
textInputBlurText: {
},
textInputHelper: {
},
emailExtraTextInputHelper: {
},
textInputError: {
},
emailExtraTextInputError: {
},
// other styles...
});
const styles_576_767 = StyleSheet.create({
// 576 to 767
});
const styles_768_ = StyleSheet.create({
// 768; goes to 1024;
});
const currentStyles = (width, stylesInitial = { ...styles__575 }, styles576 = { ...styles_576_767 }, styles768 = { ...styles_768_ }) => {
let styles = {};
if (width < 576) {
// ...
}
else if ((width >= 576) && (width < 768)) {
// ...
}
else if (width >= 768) {
// ...
}
return styles;
};
I tried mentioned approach and want a better answer.
CodePudding user response:
First, I think you want global styles, so that you can access it from anywhere and you can also be able to execute needed code.
Make sure you use useMemo
, useCallback
in right manner, for better performance.
Move all Schema
and Styles
and Methods
of your screens inside the reusableMethods.js
file (at most case). It will act like the controller of all screens
of your app, also make a demo method which return a tiny component and this method execute another method, so that you can get styles for different dimentions(see below code)
Store only changeable and needed properties in state
variables.
Is code reusing approach of yours, correct?
I can't say about that. I will say that it depends on developer choice.
you can try like below:
reusableMethods.js
// import all schema, style variants, utility methods and other
let screenStyles = {};
const executeDimensionBasedMethods = (width, screenName) => {
if (screenName === 'a_screen_name') screenStyles[screenName] = currentStyles(width, otherParameter);
// else if()
// ...
};
export const renderDimension = (width, screenName) => {
executeDimensionBasedMethods(width, screenName);
return (
<Text style={{ width: 0, height: 0 }}></Text>
);
};
// all method definitions and logics
export const renderReusableTextInput = (
state,
setState,
inputRef,
screenName
) => {
return (
<ReusableTextInput
inputName={state.name}
inputLabel={state.label}
inputValue={state.value}
inputRef={inputRef}
secureTextEntry={state.secureTextEntry}
textInputContainerWarperStyle={{ ...screenStyles[screenName].textInputContainerWarper, ...screenStyles[screenName][`${state.name}ExtraTextInputContainerWarper`] }}
textInputContainerStyle={state.styleNames.textInputContainer || { ...screenStyles[screenName].textInputContainer }
textInputLabelStyle={state.styleNames.textInputLabel || { ...screenStyles[screenName].textInputLabel }
textInputStyle={state.styleNames.textInput || { ...screenStyles[screenName].textInput }
textInputHelperStyle={{ ...screenStyles[screenName].textInputHelper, ...screenStyles[screenName][`${state.name}ExtraTextInputHelper`] }}
textInputErrorStyle={{ ...screenStyles[screenName].textInputError, ...screenStyles[screenName][`${state.name}ExtraTextInputError`] }}
helperText={state.helperText}
inputError={state.error}
onFocus={() => handleFocus(state, setState, screenStyles[screenName])}
onChangeText={(text) => handleChangeText(state, setState, text)}
onBlur={() => handleBlur(state, setState, screenStyles[screenName])}
/>
);
};
Main.js
const Main = () => {
const { width: windowWidth, height: windowHeight} = useWindowDimensions();
const minimumWidth = (windowWidth <= windowHeight) ? windowWidth : windowHeight;
const [email, setEmail] = useState({
name: 'email', // unchangeable
label: 'Email', // unchangeable
value: '',
error: '',
trailingIcons: [require('../../file/image/clear_trailing_icon.png')], // unchangeable
helperText: 'only .com, .net and .org allowed', // unchangeable
styleNames: {
textInputContainer: undefined,
textInputLabel: undefined,
textInput: undefined,
},
});
// other states
const references = useRef({});
return (
<>
{
useMemo(() => renderDimension(minimumWidth), [minimumWidth])
}
<View style={{ // inline style}}>
{
useMemo(() => renderReusableTextInput(email, setEmail, references.current, 'nameofscreen'), [email, minimumWidth])
}
</View>
</>
}
export default memo(Main);