React code-smells: Big form components
Big components suggest that there might be too much going on inside. However sometimes it is hard to remove/extract the logic, as it really belongs there. That’s the case often with form components. In such cases we can extract related groups of logic into hooks.
function QuestionForm({ defaultQuestion }) {
const [questionData, setQuestionData] = useState(defaultQuestion);
// ====== stuff related to image refresh ======
const [imageTimer, setImageTimer] = useState({});
useEffect(
function refreshFrontendSignedImages() {
// logic for refreshing
},
[]
);
useEffect(function setupRefreshForInitialImages() {
// logic to refresh setup
}, []);
// ====== stuff related to submitting ======
const dispatch = useDispatch();
const [questionValidationErrors, setQuestionValidationErrors] = useState([]);
const cleanupSaveActions = useCallback(() => {
// cleanup handler logic
}, []);
const onSubmit = useCallback(() => {
// submit handler logic
}, []);
// ====== stuff related to handling changes ======
const handleTitleChange = useCallback(({ target }) => {
// handle title change
}, []);
const handleChoicesUpdate = useCallback((choice, index) => {
// handle choices update
}, []);
const handleTopicsUpdate = useCallback((topicIds) => {
// handle topic update
}, []);
return <form>Some Form UI</form>;
}
After extracting imageRefresh, submitHandlers and changeHandlers logic to hooks we have certain benefits:
- more readable component without dozens of functions flying around
- functions are grouped by their utility, so it’s easier to reason about them as we don’t have submit functions surrounded by change handlers
- whenever you need to work on part of the functionality (like image refresh) you have all functions in one place
- hooks can be reused (but this is not the main point of this refactoring)
function QuestionForm({ defaultQuestion }) {
const [questionData, setQuestionData] = useState(defaultQuestion);
const { setImageTimer } = useSignedImagesRefresh({
setQuestionData,
defaultQuestion,
});
const {
onSubmit,
onSubmitAndCreateAnother,
validationErrors,
} = useQuestionFormSubmitHandlers({ questionData });
const {
handleTitleChange,
handleChoicesUpdate,
handleTopicsUpdate,
} = useQuestionFormChangeHandlers({ setQuestionData });
return <form>Some Form UI</form>;
}
Tweet