React keep focus on re-rendering input - reactjs

I am building an e-commerce web app, and have run into a problem making an array of inputs. Inside DescHTML I am trying to handle onChange event, but on each update the focus on the element is lost, making it very annoying to type. Does anyone have any solution or different aproach to this whole problem? Thanks in advance.
import {useState} from 'react'
export default function UploadForm() {
const [name, setName] = useState('')
const [category, setCategory] = useState('')
const [film, setFilm] = useState('')
const [price, setPrice] = useState('')
const [descArr, setDescArr] = useState([''])
function DescHTML() {
return (
<div>
{ descArr.map((item, i) =>
<input type="text" placeholder="TEST" key={i} value={item} onChange={(e) => {
e.preventDefault()
const newArr = [...descArr]
newArr[i] = e.target.value
setDescArr(newArr)
} } /> )}
</div>
)
}
console.log(descArr)
return (
<div>
<form method="POST" action="http://localhost:3500/api/upload" encType='multipart/form-data'>
<input type="file" name="image" />
<input type="text" value={name} name="name" onChange={(e) => setName(e.target.value)} placeholder="Product name" />
<input type="text" value={category} name="category" onChange={(e) => setCategory(e.target.value)} placeholder="Category" />
<input type="text" value={film} name="film" onChange={(e) => setFilm(e.target.value)} placeholder="Film" />
<input type="text" value={price} name="price" onChange={(e) => setPrice(e.target.value)} placeholder="Price" />
<DescHTML />
<hr />
{/*<input type="submit" value="Submit" />*/}
</form>
<button onClick={() => setDescArr([...descArr, ''])}>+</button>
</div>
)
}

Move your descArr and button inside DescHTML check below code you can check more info here.
function DescHTML() {
const [descArr, setDescArr] = useState([""]);
return (
<div>
{descArr.map((item, i) => (
<input
key={i}
type="text"
placeholder="TEST"
value={item}
onChange={(e) => {
e.preventDefault();
const newArr = [...descArr];
newArr[i] = e.target.value;
setDescArr(newArr);
}}
/>
))}
<br />
<button onClick={() => setDescArr([...descArr, ""])}>+</button>
</div>
);
}

First of all - move DescHTML out of UploadForm:
function DescHTML({descArr, setDescArr}) {
return (
<div>
{descArr.map((item, i) =>
<input type="text" placeholder="TEST" key={i} value={item} onChange={(e) => {
e.preventDefault()
const newArr = [...descArr]
newArr[i] = e.target.value
setDescArr(newArr)
}}/>)}
</div>
)
}
and use it in <UploadForm> like this
<DescHTML descArr={descArr} setDescArr={setDescArr}/>
The other problem is the + button which steals the focus on click. Adding onMouseDown handler will fix this.
<button onMouseDown={(e) => e.preventDefault()} onClick={() => setDescArr([...descArr, ''])}>+</button>

Related

Force one selection checkboxe with REACT

how can I force only one check among multiple checkboxes ? For now I can select A, B and C but I only want to select ONE choice no more.
Here is my code :
const TabContent = ({ name, typeText }) => {
const [a, setA] = useState(false)
const [b, setB] = useState(false)
const [c, setC] = useState(false)
function handleChange(e) {
e.preventDefault()
}
return (
<form onSubmit={handleChange} >
{a}
{b}
{b}
<input type="checkbox" onChange={(e) => setA(!a)} /> <label> A </label>
<input type="checkbox" onChange={(e) => setB(!b)} /> <label>B</label>
<input type="checkbox" onChange={(e) => setC(!C)} /> <label>C</label>
</form>
{
(a || b) ?
(<div>
<p className="mt-6 py-1">My choices </p>
<SafeAreaView>
<TextInput
onChangeText={(value) => setText(value)}
value={text}
/>
</SafeAreaView>
</div >
)
: ('')
}
{
c?
(...)
}
</div >
);
};
I think you want to use radio input
Example to illustrate this:
https://codesandbox.io/s/elegant-tess-wu7sl7?file=/src/App.js:0-794
import React, { useState } from "react";
export const TabContent = ({ name, typeText }) => {
const [radio, setRadio] = useState(false);
function handleChange(e) {
e.preventDefault();
}
return (
<form onSubmit={handleChange}>
<input
type="radio"
value="A"
onChange={(e) => setRadio(e.target.value)}
checked={radio === "A"}
/>
<label> A </label>
<input
type="radio"
value="B"
checked={radio === "B"}
onChange={(e) => setRadio(e.target.value)}
/>
<label>B</label>
<input
type="radio"
value="C"
checked={radio === "C"}
onChange={(e) => setRadio(e.target.value)}
/>
<label>C</label>
</form>
);
};
export default TabContent;
This way you only keep track of one state.
You can refactor your state with object state instead of using 3 states
const TabContent = ({ name, typeText }) => {
const [check, setCheck] = useState({selected: "", checked: false})
const handleCheckbox = (type) => {
if(type === check.selected && check.checked) {
setCheck({...check, checked: false})
} else {
setCheck({selected: type, checked: true})
}
}
function handleChange(e) {
e.preventDefault()
}
return (
<form onSubmit={handleChange} >
{check.selected}
<input type="checkbox" onChange={(e) => handleCheckbox("a")} /> <label> A </label>
<input type="checkbox" onChange={(e) => handleCheckbox("b")} /> <label>B</label>
<input type="checkbox" onChange={(e) => handleCheckbox("c")} /> <label>C</label>
</form>
{
(check.selected === ("a" || "b")) ?
(<div>
<p className="mt-6 py-1">My choices </p>
<SafeAreaView>
<TextInput
onChangeText={(value) => setText(value)}
value={text}
/>
</SafeAreaView>
</div >
)
: ('')
}
{
(check.selected === "c") ?
(...)
}
</div >
);
};

The input value codes refused to work in react js

What could be wrong with these codes? The input is not working once I add [event.target.name]. If I remove that line of codes, I can see the contents that I type inside the input box. The issue is that I want it to work with this code [event.target.name]. This will enable me pick each inputbox values as entered by the user. There are three input boxes and I need to capture the three values in my useState. Any help on how to write it better?
import React, { useState } from 'react';
import "./addbirthday.css";
import "./home.css";
export default function Addbirthday({setShowAdd}) {
const [inputDatas, setInputData] = useState([
{fullName: '', fullDate: '', relationship: ''}
]);
const handlePublish = () =>{
console.log("Hi ", inputDatas)
}
const handleChangeInput = (index, event) =>{
const values = [...inputDatas];
values[index][event.target.name] = event.target.value
setInputData(values)
}
return (
<div className="container">
<div className= { closeInput? "addContainer" :"addWrapper homeWrapper "}>
<i className="fas fa-window-close" onClick={closeNow} ></i>
{inputDatas.map((inputData, index)=> (
<div key={index} className="addbirth">
<label>Name</label>
<input type="text" name="Fname" placeholder='Namend' value=
{inputData.fullName} onChange = {event => handleChangeInput(index, event)} />
<label>Date</label>
<input type="date" placeholder='Date' name="fdate" value=
{inputData.fullDate} onChange = {event => handleChangeInput(index, event)} />
<label>Relationship</label>
<input type="text" placeholder='Friend' name="frelationship" value=
{inputData.relationship} onChange = {event => handleChangeInput(index, event)}/>
</div>
))}
<button className="addBtn" onClick={handlePublish} >Add</button>
</div>
</div>
)
}
You are not setting the name correctly
Change your input tags name to same as state object name meaning
<input name='fullname' />
I have modified your code a bit. Make it as your own and get it done
Upvote my answer if it helps
https://codesandbox.io/s/jolly-khayyam-51ybe?file=/src/App.js:0-1711
import React, { useState } from "react";
export default function Addbirthday({ setShowAdd }) {
const [inputDatas, setInputData] = useState([
{ Fname: "", fdate: "", frelationship: "" }
]);
const handlePublish = () => {
console.log("Hi ", inputDatas);
};
const handleChangeInput = (index, event) => {
const values = [...inputDatas];
values[index][event.target.name] = event.target.value;
setInputData(values);
console.log(values[index][event.target.name]);
};
return (
<div className="container">
<div className={"addContainer addWrapper homeWrapper"}>
<i className="fas fa-window-close"></i>
{inputDatas.map((inputData, index) => (
<div key={index} className="addbirth">
<label>Name</label>
<input
type="text"
name="Fname"
placeholder="Namend"
value={inputData.fullName}
onChange={(event) => handleChangeInput(index, event)}
/>
<label>Date</label>
<input
type="date"
placeholder="Date"
name="fdate"
value={inputData.fullDate}
onChange={(event) => handleChangeInput(index, event)}
/>
<label>Relationship</label>
<input
type="text"
placeholder="Friend"
name="frelationship"
value={inputData.relationship}
onChange={(event) => handleChangeInput(index, event)}
/>
</div>
))}
<button className="addBtn" onClick={handlePublish}>
Add
</button>
</div>
</div>
);
}

React Get User Info.(Input Values) On a Button Click

I've made a simple resume portal. What I want is to get all the inputs values displayed on a screen on submit. This all should be done when button(Generate CV) is clicked.
Here's my code below:
Child component ( src -> Routes -> UserForm -> Components -> UserDetails -> index.js )
import React from 'react'
import './style.scss';
import { Row, Col } from 'react-bootstrap'
const UserDetails = (props) => {
const { wrkExpTxtArea, AcQuTxtArea, clickToAdd, clickToRmv, addAcQuTxtArea, rmvAcQuTxtArea, inputChangeHandler } = props
return (
<>
<div className='UserDetails'>
<Row>
<Col lg='6'>
<div className='persnlInfo'>
<h4>
Personal Information
</h4>
<p>Your Name</p>
<input onChange={() => inputChangeHandler('name')} type="text" placeholder="Enter here" />
<p>Your Contact</p>
<input type="text" placeholder="Enter here" />
<p>Your Address</p>
<textarea className='formAddress' rows="5" cols="10" placeholder="Enter here" />
<p id='impLinks'>Important Links</p>
<p>Facebook</p>
<input type="text" placeholder="Enter here" />
<p>Instagram</p>
<input type="text" placeholder="Enter here" />
<p>Linkedin</p>
<input type="text" placeholder="Enter here" />
</div>
</Col>
<Col lg='6'>
<h4>
Professional Information
</h4>
<p>Objective</p>
<textarea className='formObjective' rows="5" cols="10" placeholder="Enter here" />
<p>Work Experience</p>
{wrkExpTxtArea.map(item => (
<textarea className='formWrkExp' value={item.value} rows="3" cols="10" placeholder="Enter here" />
))}
<div className='Button' >
<input type='button' value='Add' onClick={clickToAdd} />
<input type='button' value='Remove' onClick={clickToRmv} />
</div>
<p id='AcQu'>Academic Qualification</p>
{AcQuTxtArea.map(item => (
<textarea className='formAcQu' value={item.value} rows="3" cols="10" placeholder="Enter here" />
))}
<div className='Button' >
<input type='button' value='Add' onClick={addAcQuTxtArea} />
<input type='button' value='Remove' onClick={rmvAcQuTxtArea} />
</div>
</Col>
<Row>
<div className='sbmtButton'>
<input type='button' value='Generate CV' />
</div>
</Row>
</Row>
</div>
</>
)
}
export default UserDetails;
Parent component ( src -> Routes -> UserForm -> index.js )
import React from "react";
import Pages from "../../Components/HOC/Page/index";
import UserDetails from "../UserForm/Components/UserDetails/index";
class UserForm extends React.Component {
state = {
wrkExpTxtArea: [{ text: "" }],
AcQuTxtArea: [{ text: "" }],
inputValues: [{name: 'name', value: ''}],
};
inputChangeHandler = (e,inputName) => {
let updatedInputs = [...this.state.inputValues]
let changedInputValuesIndex = updatedInputs.findIndex(input => input.name === inputName)
if (changedInputValuesIndex > -1) {
let updatedInputValue =
{...updatedInputs[changedInputValuesIndex]}
updatedInputValue.value = e.target.value
updatedInputs[changedInputValuesIndex] = updatedInputValue
}
this.setState({inputValues: updatedInputs})
}
addTextArea = () => {
let updatedTextArea = [...this.state.wrkExpTxtArea];
updatedTextArea.push({ text: "" });
this.setState({ wrkExpTxtArea: updatedTextArea });
};
rmvTextArea = () => {
let updatedTextArea = [...this.state.wrkExpTxtArea];
if (updatedTextArea.length > 1) {
updatedTextArea.pop({ text: "" });
}
this.setState({ wrkExpTxtArea: updatedTextArea });
};
addAcQuTextArea = () => {
let updatedTextArea = [...this.state.AcQuTxtArea];
updatedTextArea.push({ text: "" });
this.setState({ AcQuTxtArea: updatedTextArea });
};
rmvAcQuTextArea = () => {
let updatedTextArea = [...this.state.AcQuTxtArea];
if (updatedTextArea.length > 1) {
updatedTextArea.pop({ text: "" });
}
this.setState({ AcQuTxtArea: updatedTextArea });
};
render() {
return (
<>
<Pages showHeader showFooter>
<UserDetails inputChangeHandler={this.inputChangeHandler} wrkExpTxtArea={this.state.wrkExpTxtArea} clickToAdd={this.addTextArea} clickToRmv={this.rmvTextArea}
AcQuTxtArea={this.state.AcQuTxtArea} addAcQuTxtArea={this.addAcQuTextArea} rmvAcQuTxtArea={this.rmvAcQuTextArea} />
</Pages>
</>
);
}
}
export default UserForm;
Output:
I'm new to programming and getting values of user inputs seems insanely complicated to me. I'm little aware that this can be achieved using state , props etc. But I really have no idea about Where and What code is to place. I need help. That’s it!
You can use useRef hook and give a reference to each of input element.
For Example
const name = useRef();
const handleSubmit = () => {
if(name.current && name.current.value){
console.log(name.current.value) // input element's value
}
}
return (<div>
<input type="text" ref={name} />
<button onClick={handleSubmit}> Submit </button>
</div>)
add an onChange prop to the input tag like this:
const [inputValue, setInputValue] = useState('')
const inputChangeHandler = (e) => {
// e argument has received by default from onChange
const newValue = e.target.value
setInputValue(newValue)
}
<input onChange={inputChangeHandler} />
whenever you start changing the value of the input, inputChangeHandler function will trigger and then update your state
index.js
import React, { useState } from "react";
import Pages from "../../Components/HOC/Page/index";
import UserDetails from "../UserForm/Components/UserDetails/index";
const initialData = {
name: '',
contact: '',
address: '',
facebook: '',
instagram: '',
linkedin: '',
objective: '',
workExperience: [],
academicQualification: [],
}
const UserForm = () => {
// holds all the form data from child component "UserDetails"
const [formData, setFormData] = useState(initialData)
const handleSubmit = () => {
// submit handler
alert(JSON.stringify(formData, undefined, 4))
}
return (
<>
<Pages showHeader showFooter>
<UserDetails form={formData} setter={setFormData} onSubmit={handleSubmit} />
</Pages>
</>
)
}
export default UserForm;
UserDetails
import React, { useState } from 'react'
import './style.scss';
import { Row, Col } from 'react-bootstrap'
const UserDetails = ({ form, setter, onSubmit }) => {
const hanldeOnChange = (e) => {
setter(prev => {
// access property by input element's name
// update the state on parent component
prev[e.target.name] = e.target.value;
return { ...prev } // return copy after updating
})
}
const [listTypeElements, setListTypeElements] = useState({ workExperience: '', academicQualification: '' })
const handleListInput = (property) => {
setter(prev => {
prev[property].push(listTypeElements[property]);
return { ...prev }
})
setListTypeElements(prev => {
prev[property] = ''
return { ...prev }
})
}
const handleRemoveItem = (property) => {
setter(prev => {
prev[property].pop();
return { ...prev }
})
}
return (
<>
<div className='UserDetails'>
<Row>
<Col lg='6'>
<div className='persnlInfo'>
<h4>
Personal Information
</h4>
<p>Your Name</p>
<input type="text" placeholder="Enter here" onChange={hanldeOnChange} name='name' />
<p>Your Contact</p>
<input type="text" placeholder="Enter here" onChange={hanldeOnChange} name='contact' />
<p>Your Address</p>
<textarea className='formAddress' rows="5" cols="10" placeholder="Enter here" onChange={hanldeOnChange} name='address' />
<p id='impLinks'>Important Links</p>
<p>Facebook</p>
<input type="text" placeholder="Enter here" onChange={hanldeOnChange} name='facebook' />
<p>Instagram</p>
<input type="text" placeholder="Enter here" onChange={hanldeOnChange} name='instagram' />
<p>Linkedin</p>
<input type="text" placeholder="Enter here" onChange={hanldeOnChange} name='linkedin' />
</div>
</Col>
<Col lg='6'>
<h4>
Professional Information
</h4>
<p>Objective</p>
<textarea className='formObjective' rows="5" cols="10" placeholder="Enter here" onChange={hanldeOnChange} name='objective' />
<p>Work Experience</p>
{form.workExperience.map((value) =>
<textarea className='formWrkExp' value={value} rows="3" cols="10" disabled={true} />)}
<textarea className='formWrkExp' value={listTypeElements['workExperience']} rows="3" cols="10" placeholder="Enter here" onChange={(e) => setListTypeElements(prev => {
prev['workExperience'] = e.target.value;
return { ...prev }
})} />
< div className='Button' >
<input type='button' value='Add' onClick={() => handleListInput('workExperience')} />
<input type='button' value='Remove' onClick={() => handleRemoveItem('workExperience')} />
</div>
<p id='AcQu'>Academic Qualification</p>
{form.academicQualification.map((value) =>
<textarea className='formAcQu' value={value} rows="3" cols="10" disabled={true} />)}
<textarea className='formAcQu' value={listTypeElements['academicQualification']} rows="3" cols="10" placeholder="Enter here" onChange={(e) => setListTypeElements(prev => {
prev['academicQualification'] = e.target.value;
return { ...prev }
})} />
< div className='Button' >
<input type='button' value='Add' onClick={() => handleListInput('academicQualification')} />
<input type='button' value='Remove' onClick={() => handleRemoveItem('academicQualification')} />
</div>
</Col>
<Row>
<div className='sbmtButton'>
<input type='button' value='Generate CV' onClick={onSubmit} />
</div>
</Row>
</Row>
</div>
</>
)
}
export default UserDetails;

Clear value into input using useState or useRef (React)

I got hook:
const [myName, setMyName] = useState("");
const myNameRef = useRef();
Then I have form:
<form onSubmit={(e) => addVist(e, user.id)}>
<input type="text" name="myName" ref={myNameRef} onChange={e => setMyName(e.target.value)} />
<input type="submit" value="Run" />
</form>
And method:
const addVist = (e, userId) => {
e.preventDefault();
console.log(myName)
//some code....
//clear value form
setMyName("");
//setMyName('');
//setMyName(e.target.value = "");
//myNameRef.current.value("");
}
But the setMyName("") is not working - still I see value inside input.
You missed binding myName as value attribute of the input tag.
<input type="text" name="myName" value={myName} ref={myNameRef} onChange={e => setMyName(e.target.value)} />
Here is a complete example of clearing input using state OR a reference:
export default function App() {
const [value, setValue] = useState("");
const inputRef = useRef();
return (
<>
<input value={value} onChange={(e) => setValue(e.target.value)} />
<input ref={inputRef} />
<button
onClick={() => {
setValue("");
inputRef.current.value = "";
}}
>
Clear
</button>
</>
);
}
Refer to Controlled VS Uncontrolled components.
On your text input you should pass myName into the value attribute like so
<input type="text" name="myName" value={myName} ref={myNameRef} onChange={e => setMyName(e.target.value)} />
You forgot to add myName as value.
<input type="text" name="myName" value={myName} ref={myNameRef} onChange={e => setMyName(e.target.value)} />

React Hooks update props from react-redux

I am having an issue with props updating with Redux. I am using redux-promise-middleware, and am making a login request. My hook receives the initialState. I can see the dispatch and reducer are being correctly updated when I console.log in the mapStateToProps function. However, the props are never updated with redux.
const Login = (props) => {
const [email, updateEmail] = useState('')
const [password, updatePassword] = useState('')
const [firstName, updateFirstName] = useState('')
const [lastName, updateLastName] = useState('')
const [loginToggle, updateLoginToggle] = useState(true)
async function handleLogin() {
const loginInfo = {email, password}
await props.loginUser(loginInfo)
if (props.user.loggedIn) props.history.push('/dashboard');
}
return (
<div className="login-page">
<div className="login-register-container">
{ loginToggle ?(
<div className="login-container">
<h2>Login</h2>
<input placeholder='Email' value={email} onChange={e =>
updateEmail(e.target.value)} />
<input placeholder='Password' value={password} onChange={e => updatePassword(e.target.value)} />
<button onClick={handleLogin}> Login </button>
<p style={{cursor:"pointer"}} onClick={() => updateLoginToggle(false)}> need to register?</p>
</div>
):(
<div className="register-container">
<h2>Register</h2>
<input placeholder='First Name' value={firstName} onChange={e => updateFirstName(e.target.value)} />
<input placeholder='Last Name' value={lastName} onChange={e => updateLastName(e.target.value)} />
<input placeholder='Email' value={email} onChange={e => updateEmail(e.target.value)} />
<input placeholder='Password' value={password} onChange={e => updatePassword(e.target.value)} />
<button onClick={handleRegister}> Register </button>
<p style={{cursor:"pointer"}} onClick={() => updateLoginToggle(true)}> already have login?</p>
</div>
)}
</div>
</div>
)
}
function mapStateToProps(reduxState) {
console.log(reduxState)
return {
user: reduxState.user
}
};
export default connect(mapStateToProps, {loginUser, getUser})(Login)

Resources