Unable to store data in useState - reactjs

[Here is the view
So I have the following output.
I am unable to store the data from this form to the Array and an object.
Every time there is a change in children field there is another form that has to be stored.
I have to do this using and unique ID for each of them.
const CreateForm = () => {
const [isDisabled, setIsDisabled] = useState(false);
let [applicant, setApplicant] = useState([]);
const handleChildren = (e) => {
const udatedApplicant = { ...applicant };
udatedApplicant.childrens = e.target.value;
setApplicant({ ...udatedApplicant });
if (applicant.childrens!==0){
udatedApplicant.childrens= e.target.childrens=0;
}
};
const handleRadio = (e) => {
const udatedApplicant = { ...applicant };
udatedApplicant.maritalStatus = e.target.value;
setApplicant({ ...udatedApplicant });
};
// const finalForm = setApplicant(...applicant)
return (
<div>
<div>
<input name="firstName" placeholder="firstName" />
<input name="lastName" placeholder="lastName" />
<input type="email" name="Email" placeholder="Email" />
<div>
<label>
<input type="radio" name="Gender" value="Male" />
Male
</label>
I am able to handle all the onChanges fields but unable to store this using map in the useState applicant.
I tried it using the index, but after I store the first applicant, when I change the field married or children, I got a blank page.
Can someone help me handle this? I passed 2 hours on this and I'm still not able to store the data.
Im kinda new in React.
Any small tip would be appreciated.

Related

How do I store an image in react useState

I'm trying to add a form in which users can add text and images which is then going to be stored on the mongodb database. As of right now, I'm trying to add a section in the form where users can add images. I'm trying to figure out a way to store an image that the user uploads and send it to the backend (I'm using MERN stack).
This is my code that deals with the form, in terms of getting user input and sending it to the backend:
import { useState } from "react";
import { adminSDGOptions } from "./AdminCategoryLists";
import { adminAssingmentOptions } from "./AdminCategoryLists";
import { keywordsOptions } from "../FilterComponents/CategoryArrays/KeywordsOptions";
import Multiselect from "multiselect-react-dropdown"
import Select from 'react-select';
const ProjectAdminForm = () => {
// Adding basic info
const [sdg, setSDG] = useState('')
const [goal, setGoal] = useState('')
const [orginization, setOrginization] = useState('')
const [source, setSource] = useState('')
const [location, setLocation] = useState('')
const [published, setPublished] = useState('')
const [website_url, setWebsiteURL] = useState('')
const [assignment_type, setAssignmentType] = useState('')
const [sharepoint_link, setSharepointLink] = useState('')
const [statement, setStatement] = useState('')
const [preview_img, setPreviewImg] = useState([])
const [error, setError] = useState(null)
// Adding keywords
const [keywords, setKeywords] = useState([]);
const handleSubmit = async (e) => {
e.preventDefault() // Prevents refresh of page from happening
console.log('button clicked')
const project = {sdg, goal, orginization, source, location, published, website_url, assignment_type, keywords, sharepoint_link, statement, preview_img}
console.log(project)
// Sending form response to backend
const response = await fetch('/api/projects', {
method: 'POST',
body: JSON.stringify(project),
headers: {
'Content-Type': 'application/json'
}
})
const json = await response.json
// Checking for error
if (!response.ok) {
setError(json.error)
}
if (response.ok) {
// Reset form inputs back to empty string
setSDG('')
setGoal('')
setOrginization('')
setSource('')
setLocation('')
setPublished('')
setWebsiteURL('')
setAssignmentType('')
setKeywords([])
setSharepointLink('')
setStatement('')
setError(null)
alert('Project added!')
console.log('new project added', json)
}
}
return (
<form className="create project-form" onSubmit={handleSubmit}>
<h2 style={{"textAlign": "center"}}>Add a New Project</h2>
<hr></hr>
<label>Sustainable Development Goal:</label>
<Select
className="basic-single"
classNamePrefix="select"
placeholder="Select"
name="color"
options={adminSDGOptions}
onChange={(selection) => setSDG(selection.value)}
required
/>
<label>Description:</label>
<input
type="text"
onChange={(e) => setGoal(e.target.value)}
value={goal}
required
/>
<label>OPTIONAL - Organization:</label>
<input
type="text"
onChange={(e) => setOrginization(e.target.value)}
value={orginization}
/>
<label>OPTIONAL - Source:</label>
<input
type="text"
onChange={(e) => setSource(e.target.value)}
value={source}
/>
<label>OPTIONAL - Location:</label>
<input
type="text"
onChange={(e) => setLocation(e.target.value)}
value={location}
/>
<label>Published (YEAR ONLY):</label>
<input
type="text"
onChange={(e) => setPublished(e.target.value)}
value={published}
required
/>
<label>OPTIONAL - Website URL:</label>
<input
type="text"
onChange={(e) => setWebsiteURL(e.target.value)}
value={website_url}
/>
<label>Assignment Type:</label>
<Select
className="basic-single"
classNamePrefix="select"
placeholder="Select"
name="color"
options={adminAssingmentOptions}
onChange={(selection) => setAssignmentType(selection.value)}
required
/>
<hr></hr>
<label>Enter Keyword(s):</label>
<Multiselect
className="multiselect-admin"
isObject={false}
onRemove={(selection) => setKeywords(selection)}
onSelect={(selection) => setKeywords(selection)}
options={keywordsOptions}
required
/>
<hr></hr>
<label>OPTIONAL - Statement (ONLY Assessment Ideas and Discussion Topics):</label>
<input
type="text"
onChange={(e) => setStatement(e.target.value)}
value={statement}
/>
<label>OPTIONAL - Qualtrics Link (ONLY Mini Case Study):</label>
<input
type="text"
onChange={(e) => setSharepointLink(e.target.value)}
value={sharepoint_link}
/>
// THIS IS THE SECTION I'M TRYING TO ADD AND AM NOT SURE HOW TO GO ABOUT DOING SO
<label>OPTIONAL - Preview image:</label>
<input
type="file"
name="preview_img"
accept="image/*"
onChange={(e) => setPreviewImg(e.target.value)}
/>
<div className="add-proj">
<button>Add Project</button>
</div>
{error && <div className="error">{error}</div>}
</form>
)
}
export default ProjectAdminForm
The main thing I'm trying to get working is the preview_img stuff, I'm able to ask the user for an image through <input/> but then when I store itin my useState which is set up like this const [preview_img, setPreviewImg] = useState([]), it doesn't save the actual image, rather a string which looks like this:
preview_img: "C:\\fakepath\\banner2 (2).jpg"
I'm not sure how to save the actual image and then send it to the backend in my handleSubmit function since it appears I can't just include the state name (preview_img) in the object I'm sending to the backend.
You can reach and upload the image in onChange function. If you want to use it by accessing local url, you can create and store its local url in a state.
const [imageURL,setImageURL] = useState()
onChange={(event) => {
let file = event.target.files[0]
yourUploadFunction(file, url)
setImageURL(URL.createObjectURL(file))
}}

How do I write an edit-file for mixed data in React

I want to update an article with image.
I am using a mern-stack with redux-toolkit.
I tried to bring the data from the database into the inputfields by using useEffect() and that works, and currently I get no error anymore, but when I press update, I get an alert:
localhost:3000 includes undefined
and then the pending of my updatefunction stops. So nothing is updated. The preview of my picture works.
Can someone of the experienced people tell me the right way, to write this edit file?
Here is my react-component(current state):
const MainnewsEdit = () => {
const {mainnews, isLoading, isError, message} = useSelector((state)=>state.mainnews);
const dispatch = useDispatch();
const {id} = useParams();
useEffect(()=>{
if(isError){
window.alert(message);
}
dispatch(getMainNews(id))
}, [isError, message, dispatch,id]);
const savedData = {
ressort:"",
theme:"",
title:"",
content:"",
}
const [data, setData] = useState(savedData);
useEffect(()=>{
if(mainnews){
setData({
ressort: mainnews.ressort,
theme: mainnews.theme,
title: mainnews.title,
content:mainnews.content,
})
}
}, [mainnews]);
//img
const [fileData, setFileData] = useState({img:""})
const {img} = fileData;
const fileInput = useRef(img);
const fileChange = (e)=>{
const file = fileInput.current.files[0];
setFileData(file);
handlePreview(file)
}
console.log(fileData);
const [preview, setPreview] = useState(false)
const handlePreview = (file)=>{
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = ()=>{
setPreview(reader.result);
}
}
const {ressort, theme, title, content} = data;
console.log(data);
const onSubmit = (e)=>{
e.preventDefault();
const mainnewsData = new FormData();
mainnewsData.append("ressort", data.ressort);
mainnewsData.append("theme", data.theme);
mainnewsData.append("title", data.title);
mainnewsData.append("content", data.content);
mainnewsData.append("img", fileData);
for(let value of mainnewsData){
console.log(value);
}
dispatch(updateMainNews(mainnewsData))
}
That is my form:
<MainNewsForm onSubmit={onSubmit}>
<Formgroup>
<Label htmlFor="img">Image</Label>
<Input type="file" name="img" id="img"style={{background:"var(--blue)", color:"var(--white)"}} accept=".png, .jpg" onChange={fileChange} ref={fileInput}/>
{preview ? <img src={preview} alt={preview} title={preview} style={{height:"200px", width:"400px"}}/> :
<img src={mainnews.img} alt="savedImg" title="savedImg" style={{height:"200px", width:"300px"}}/>}
</Formgroup>
<Formgroup>
<Label htmlFor="ressort">Ressort</Label>
<Input type="text" name="ressort" id="ressort" defaultValue={ressort} onChange={(e)=>setData({...data, ressort: e.target.value})}/>
</Formgroup>
<Formgroup>
<Label htmlFor="theme">Theme</Label>
<Input type="text" name="theme" id="theme" defaultValue={theme} onChange={(e)=>setData({...data, theme: e.target.value})}/>
</Formgroup>
<Formgroup>
<Label htmlFor="title">Title</Label>
<Input type="text" name="title" id="title" defaultValue={title} onChange={(e)=>setData({...data, title: e.target.value})}/>
</Formgroup>
<Formgroup>
<Label htmlFor="content">Content</Label>
<Textarea type="text" name="content" id="content" defaultValue={content} onChange={(e)=>({...data, content: e.target.value})}></Textarea>
</Formgroup>
<ButtonHolder>
<UpdateButton type="submit">Update</UpdateButton>
</ButtonHolder>
</MainNewsForm>
onChange={updateData} does not work since your change handler is written as a higher order function that returns a change handler that is custom for the specific inputs. onChange={updateData("ressort")} etc. should work however.
Couple of unrelated things I'd like to mention:
Using capitalized html tags like <Input looks a bit confusing, like you're using Material UI. The convention is that those are your own classes/component names or come from a library. I'd stick to lowercase html tags.
I would not put FormData in redux. If there is an async action that calls the backend, then somewhere in the action creator (or some sort of API client) is a better place to transform the data, if the API expects classic FormData. React doesn't need to be concerned with that.

Change input values bases on other input onChange

Let's say I want to create a Converter, which means the input value should be changed based on another one.
just to see what I want to do in action https://calolocosta.github.io/romanNumeralsConverter/.
here's what I tried so far but couldn't make it
function LightBulb() {
let [input1, setInput1] = useState("");
let [input2, setInput2] = useState("");
const handleInput1 = (e) => {
setInput2(e.target.value);
};
const handleInput2 = (e) => {
setInput1(e.target.value);
};
return (
<div className="App">
<input
type="text"
value={input2}
onChange={(e) => handleInput1(e)}
placeholder="example 1000"
/>
<input
type="text"
value={input1}
onChange={(e) => handleInput2(e)}
placeholder="example MCMXC"
/>
</div>
);
}
so what I want is to change the input2 value when input1 is typing and vice versa.
Here's the codesandbox that I have been working on: https://codesandbox.io/s/react-hooks-usestate-forked-8o257, any idea would appreciate it.
I guess you will do the rests of the logic for that conversion. But as far as the inputs go and their interaction that needs to change the other one, here is the code changed:
function LightBulb() {
let [input1, setInput1] = useState("");
let [input2, setInput2] = useState("");
const handleInput1 = (e) => {
setInput1(e.target.value);
setInput2("Converted value");
};
const handleInput2 = (e) => {
setInput2(e.target.value);
setInput1("Converted value");
};
console.log(input2);
return (
<div className="App">
<input
type="text"
value={input1}
onChange={(e) => handleInput1(e)}
placeholder="example 1000"
/>
<input
type="text"
value={input2}
onChange={(e) => handleInput2(e)}
placeholder="example MCMXC"
/>
</div>
);
}
You need to set value for corresponding input anyways. But value for the counterpart needs to be set with converted value.
Here is codesandbox also: https://codesandbox.io/s/react-hooks-usestate-forked-667fr?file=/src/index.js:100-777

Edit Form React JS

I´m making an edit form with React js. I have multiple components in the form. In one of the son components, I pass all the changes that I`ve done to a hook in the main component to do the changes in firebase.
Father Component
const [changes, setChanges] = useState({});
const updateGenData = (genData) => {
setChanges(genData);
}
Son Component(I take all the info from the father, via props)
const UpdateProfileGenData = (props) => {
const [values, setValues] = useState({});
const [changes, setChanges] = useState({});
useEffect(() => {
setValues(props);
},[props]);
const {field1, field2, field3} = values;
useEffect(() => {
props.updateGenData(changes);
},[changes]);
const handleChange= e => {
setValues({
...values,
[e.target.name]: e.target.value
});
setChanges({
...changes,
[e.target.name]: e.target.value
})
}
return (
<input type="text" name="field1" value={field1} onChange={handleChange}/>
<input type="text" name="field2" value={field2} onChange={handleChange}/>
<input type="text" name="field3" value={field3} onChange={handleChange}/>
);
}
export default UpdateProfileGenData;
When I pass the values ​​from the child component to the parent it doesn't allow me to edit the child form . I can´t change any field.
Any suggestions??
Regards
Why do you use useEffect so often? The problem may be that you often use useEffect and somewhere you overwrite the data correctly.
Can be made easier:
Father Component
const [changes, setChanges] = useState({});
const updateGenData = (genData) => setChanges({...changes, ...genData});
Son Component
const UpdateProfileGenData = ({field1, field2, field3, updateGenData}) => {
const handleChange= e => updateGenData({
[e.target.name]: e.target.value,
});
return (
<input type="text" name="field1" value={field1} onChange={handleChange}/>
<input type="text" name="field2" value={field2} onChange={handleChange}/>
<input type="text" name="field3" value={field3} onChange={handleChange}/>
);
}
export default UpdateProfileGenData;

DOM does not update on value change

I am trying to set up a simple form using a function component using a next.js project:
const Form = () => {
let error = false
const handleNameSubmit = (e) => {
e.preventDefault()
const name = e.target.name.value.trim()
if(!! name.length) {
error = false
} else {
error = 'Please enter your name'
}
}
return (
<>
<form onSubmit={handleNameSubmit}>
<h1>I’d like to know how to address you,
please type in your name</h1>
<input type="text" name="name" placeholder="Your name"/>
{!!error && (<p>{error}</p>)}
<button type="submit">Next</button>
</form>
</>
)
}
I am doing some trivial validation i.e. checking if any value is entered in the name input and displaying an error, if the field is empty.
However, when I set the value of error on page load to be something, it shows in the DOM, but if I manipulate it later, the DOM does not update. I am new to next.js.
You have to use state variable to achieved your goal. Simply convert error in state variable and it will work.
const Form = () => {
const [error, setError] = useState(false);
const handleNameSubmit = (e) => {
e.preventDefault();
const name = e.target.name.value.trim();
setError(name.length ? false : 'Please enter your name');
}
return (
<>
<form onSubmit={handleNameSubmit}>
<h1>I’d like to know how to address you,
please type in your name</h1>
<input type="text" name="name" placeholder="Your name" />
<button type="submit">Next</button>
{error && <p>{error}</p>}
</form>
</>
)
}
I have created small demo for you.
https://stackblitz.com/edit/react-7kat5c
Hope this will help you!

Resources