Reputation: 229
how can I optimize/ factor my code. I have two cases 'exist' and 'new',depending on this value I made a different display. At the beginning I've just create a general value called user
, pwd
... (18 more) but the issue was that when I fill a field (user for example) for case 'exist' then the field 'user' is filled too - for the other case (i.e new) although they should not be the same.
Is there a way to factor my code please ?
export default function Choice() {
const [existUser, setExistUser] = useState("");
const [newUser, setNewUser] = useState("");
const [existPwd, setPwd] = useState("");
const [newPwd, setPwd] = useState("");
// There are 20 in total with the exact same pattern (exist and new)
...
let handleSubmit = async (e) => {
e.preventDefault();
try {
let res = await fetch("", {
method: "POST",
body: JSON.stringify({
existUser: existUser,
...
}),
});
let resJson = await res.json();
if (res.status === 200) {
setExistUser("");
...
setRadio(false)
message("Success")
} else {
setMessage("Error");
}
} catch (err) {
console.log(err);
}
};
return (
< >
<form onSubmit={handleSubmit}>
<input type="radio" value='exist' onChange={(e) => setRadio(e.target.value)} checked={radio === 'exist'} />
<input type="radio" value='new' onChange={(e) => setRadio(e.target.value)} checked={radio === 'new'} />
</form>
{(radio === 'exist') ?
(
<div>
<form onSubmit={handleSubmit}>
<label >
User:
<input
type="text"
value={existUser}
placeholder="User"
onChange={(e) => setExistUser(e.target.value)}
/>
</label>
</form>
</div>
)
:
('')
}
{
(radio === 'new') ?
(<div>
<form onSubmit={handleSubmit}>
//Other inputs with the exct same pattren as before - newUser...
<inputs .../>
</form>
</div>
)
:
('')
}
{(radio === ('exist')) ?
<div>
<form onSubmit={handleSubmit}>
// Exact same inputs to display as radio==='new' (above)
</form >
</div>
:
('')
}
</>
)
}
Here is my code
Upvotes: 2
Views: 522
Reputation: 107
You could create two contexts with the states you need: user
, pwd
, etc. The repeated structure could be encapsulated with a factory.
Full example on sandbox, but you will get something like this:
// FormContext.jsx
import React, { useState } from 'react';
// the two contexts you need
export const NewFormContext = React.createContext();
export const ExistFormContext = React.createContext();
// the factory that creates a provider with the same states
// but, independent and linked to different contexts
const makeFormProvider = (FormContext) => ({ children }) => {
const [user, setUser] = useState("");
const [pwd, setPwd] = useState("");
return (
<FormContext.Provider value={{pwd,user, setUser, setPwd}}>
{children}
</FormContext.Provider>
);
};
export const NewFormProvider = makeFormProvider(NewFormContext);
export const ExistFormProvider = makeFormProvider(ExistFormContext);
Then, inside the component in which you should render the Choice.jsx
- thats App.jsx
in my case - after you provide the contexts to your component
// App.jsx
<NewFormProvider>
<ExistFormProvider>
<Choice />
</ExistFormProvider>
</NewFormProvider>
Just consume them
// Choice.jsx
const newForm = useContext(NewFormContext)
const existForm = useContext(ExistFormContext)
const handleSubmit = () => {
// handle it here
}
return (
<div>
<form onSubmit={handleSubmit}>
<input type="text" id="new-user" value={newForm.user} onChange={(e) => newForm.setUser(e.target.value)} />
<input type="text" id="exist-user" value={existForm.user} onChange={(e) => existForm.setUser(e.target.value)}/>
</form>
</div>
)
P.S.: Take care when reusing code like this. Be sure these two forms will change for the same reason, respecting the SRP. If they won't, just use two separate structures from the beginning.
Upvotes: 2
Reputation: 2437
I believe there are mainly 2 ways to refactor this many-states-problem
object
state instead of single string
state1. use object
state instead of single string
state
const [radio, setRadio] = useState("");
const [existValues, setExist] = useState({});
const [newValues, setNew] = useState({});
2. use custom hook to make two states seems one (affected by context)
let [user, setUser] = useChoicValue();
let [pwd, setPwd] = useChoicValue();
for this two main way, each you can make other optimize, for example, bring reusable codes for each subject into a template, then reuse the template with subject specific props, or mix some good points from these ways
3. resusable subject template
const ExistOrNew = ({
radio,
name,
existValue,
newValue,
updateExist,
updateNew
}) => {
4. use context to reduce prop drill
const ExistOrNew = ({
radio,
name,
keyExist,
keyNew
}) => {
let newCtx = useContext(NewCtx);
let existCtx = useContext(ExistCtx);
5. use a lib that's good at handle states
things like https://react-hook-form.com/get-started
So I made 4 example refactor
and working codes here, try it yourself https://codesandbox.io/s/determined-dewdney-c2ypv4?file=/src/App.js
Upvotes: 0