Skip to content

Instantly share code, notes, and snippets.

@kwhitejr
Last active October 7, 2019 03:24
Show Gist options
  • Save kwhitejr/df3082d2a56a00b7b75365110216b395 to your computer and use it in GitHub Desktop.
Save kwhitejr/df3082d2a56a00b7b75365110216b395 to your computer and use it in GitHub Desktop.
Complex Form with React Hooks
import React, { useState } from "react";
import { useLocalStorage } from "hooks.js";
export const FormContext = React.createContext();
const defaultFormValues = {
firstName: "",
lastName: "",
longFormText: "",
// ...etc...
};
export const FormProvider = props => {
const [form, setForm] = useLocalStorage(
"form",
defaultFormValues
);
return (
<FormContext.Provider value={{ form, setForm }}>
{props.children}
</FormContext.Provider>
);
};
// Example component that utilizes FormContext
import React, { useContext } from "react";
import { FormContext } from "contexts.js";
export default function FirstNameInput() {
const { form, setForm } = useContext(FormContext);
const handleChange = key => event => {
setForm({ ...form, [key]: event.target.value });
};
return (
<input
onChange={handleChange("firstName")}
value={form.firstName}
name="firstName"
/>
)
}
// Parent Form component that optionally sets initial state with data from async call
import React, { Fragment, useState, useEffect, useContext } from "react";
import {
FormProvider,
FormContext,
} from "contexts";
import FirstName from "FirstName.js";
// ...other components
export default function FormWrapper(props) {
return (
<Fragment>
<FormProvider>
<Form {...props} />
</FormProvider>
</Fragment>
);
}
function Form(props) {
const { formId } = props.match.params;
const { form, setForm } = useContext(FormContext);
// NOTE: This useEffect probably requires optimizing
useEffect(() => {
const fetchData = async () => {
try {
// If there is no formId, then nothing to fetch
if (!formId) return;
// If there is already text, don't load async data (i.e., prefer localStorage)
if (
window.localStorage.form.longFormText !== defaultEditorState.longFormText
) {
return;
}
const res = await getFormById(formId); // async func not defined here
setForm(res);
} catch (error) {
handleError(error);
}
};
fetchData();
}, []);
return (
<Fragment>
<FirstNameInput /> // Psuedo code components
<LastNameInput />
<LongFormTextInput />
</Fragment>
);
}
import { useState } from "react";
export function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.log(error);
return initialValue;
}
});
const setValue = value => {
try {
const valueToStore =
value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
console.log(error);
}
};
return [storedValue, setValue];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment