This is the code I am using. Response is totally correct. But setState methods not updating the state and showing me the initial states that are "". What i am doing wrong? I am using them but this occurred for the very first time.
"React": "^16.2.0"
"react-dom": "^16.2.0"
const [name, setName] = useState("");
const [gender, setGender] = useState("");
const [skillSet, setSkillSet] = useState([]);
const [dob, setDob] = useState("");
useEffect(() => {
async function getStudent() {
try {
const { data } = await axios.get("/student/1");
const student = data[0];
const skills = data[1];
console.log(student[0]);
const { name: n, dob: d, gender: g } = student[0];
setName(n);
setGender(g);
setDob(d);
console.log("Logging Name", name);
console.log(n);
alert(name);
} catch (error) {}
}
getStudent();
}, []);
EDIT
Here is my complete component whose snippet i posted above. So can you guide me on this? Otherwise i have to return to class components
import React, { useState, useEffect } from "react";
import BaseInputComponent from "../Utils/InputComponentMaterialUi";
import BaseSelect from "../Utils/SelectComponentMaterialUi";
import instruments from "../InstrumentNames";
import BaseCheckBox from "../Utils/CheckBoxMaterialUi";
import axios from "axios";
const StudentProfile = () => {
const [name, setName] = useState("");
const [gender, setGender] = useState("");
const [skillSet, setSkillSet] = useState([]);
const [dob, setDob] = useState("");
useEffect(() => {
async function getStudent() {
try {
const { data } = await axios.get("/student/1");
const student = data[0];
const skills = data[1];
console.log(student[0]);
const { name: n, dob: d, gender: g } = student[0];
setName(n);
setGender(g);
setDob(d);
console.log("Logging Name", name);
console.log(n);
alert(name);
} catch (error) {
console.log(error);
console.log("Hi");
}
}
getStudent();
}, []);
return (
<div className="container" style={{ marginTop: "5rem" }}>
<form>
<div className="row">
<div className="col-md-6 col-12 col-lg-6">
<BaseInputComponent
value={name}
changeHandler={setName}
label={"Musician's Name"}
/>
</div>
<div className="col-md-6 col-12 col-lg-6">
<BaseInputComponent
changeHandler={setDob}
value={dob}
type="date"
label={"Date Of Birth"}
InputLabelProps={{
shrink: true
}}
/>
</div>
<div className="col-md-6 col-12 col-lg-6">
<BaseSelect
label={"Choose Gender"}
value={gender || ""}
changeHandler={setGender}
options={[
{ label: "Male", value: "Male" },
{ label: "Female", value: "Female" },
{ label: "Other", value: "Other" }
]}
/>
</div>
<div className="col-md-6 col-12 col-lg-6">
<BaseInputComponent label={"Osama Inayat"} />
</div>
</div>
<button type="submit" className="btn submit-button">
Update Profile Infomation
</button>
<br />
<br />
<br />
</form>
<div style={{ width: "100%", height: "2px", background: "gray" }}>
<h2 className="text-center">Select Instruments You Played</h2>
<form>
<div className="row">
{instruments.map((name, i) => (
<div className="col-md-3 col-6">
<BaseCheckBox
skillSet={skillSet}
setSkillSet={setSkillSet}
key={i}
label={name}
value={i}
/>
</div>
))}
</div>
</form>
</div>
<button onClick={() => console.log(skillSet)}>Show Object</button>
</div>
);
};
export default StudentProfile;
To expand upon my comment – a minimized example with the same idea (without async, since the version of Babel on Stack Overflow doesn't support it, sigh) works fine, so the issue is likely in the components you use within StudentProfile, not in your hooks:
function pretendAxios() {
return Promise.resolve({ data: [[{ name: "foo", dob: "1234-1234", gender: "bar" }], ["skill"]] });
}
const StudentProfile = () => {
const [name, setName] = React.useState("");
const [gender, setGender] = React.useState("");
const [skillSet, setSkillSet] = React.useState([]);
const [dob, setDob] = React.useState("");
React.useEffect(() => {
pretendAxios().then(({ data }) => {
const student = data[0];
const skills = data[1];
const { name: n, dob: d, gender: g } = student[0];
setName(n);
setGender(g);
setDob(d);
});
}, []);
return <div>{JSON.stringify({ name, gender, skillSet, dob })}</div>;
};
ReactDOM.render(<StudentProfile />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
<TextField
onChange={e => changeHandler(e.target.value)}
id="standard-required"
label={label}
defaultValue={value}
className={classes.textField}
margin="normal"
name={name}
id={id}
style={{ width: "100%" }}
{...rest}
/>
The above code i had written in me BaseInput component after changing defaultValue to value my problem solved thanks to #AKX for pointing out the problem
Related
As a Begineer in a react,i have just implementing a dynamic array field for learning but got a problem in delete operation of removing inputs fields from the row field with passing its id in deletefunction.How to overcome this problem?
Code
import React, { useState} from "react";
import "./styles.css";
const initialValues = [
{number: "",options: ""}
];
const Newrow = (props) => {
const [number, setNumber] = useState("");
const [options, setoption] = useState([]);
const addRow = () => {
let _row = {
number: "",
options: ""
};
props.setData(_row);
};
const delrow = (i) => {
data.splice(i,2)
setData({})
}
return <div>
<input
type="number"
value={number}
onChange={(e) => {
setNumber(e.target.value);
}}
/>
<input type="text"
className="input"
value={options}
onChange={e=>{setoption(e.target.value)}}
/>
<button
type="submit"
onClick={delrow}
className="btn btn-danger">remove</button>
</div>
};
export default function App(props) {
const [data, setData] = useState([]);
const addRow = (row) => {
setData([...data, row]);
};
return (
<div className="App">
{[...data, ...initialValues].map((row, idx) => {
return <Newrow setData={addRow} data={row} key={idx} delrow{idx} />;
})}
<button
type="submit"
onClick={() =>
addRow({number: "",options: "" })}
className="btn btn-success">Add</button>
</div>
);
}
i'm quite new using React, or programming actually haha.
I am practicing making an online store and I already have almost everything working correctly. My problem is that I want the customer to be able to select the size and quantity and set it on a useState to pass that information to the cart.
This is my code:
import { Image, Grid, Icon, Button, Form } from "semantic-ui-react";
import { size } from "lodash";
import classNames from "classnames";
import useAuth from "../../../hooks/useAuth";
import useCart from "../../../hooks/useCart";
import {
isFavoriteApi,
addFavoriteApi,
deleteFavoriteApi,
} from "../../../Api/favorite";
import CarouselScreenshots from "../CarouselScreenshots";
import TabsItem from "../TabsItem"
export default function HeaderItem(props) {
const { item } = props;
const { poster, title, screenshots } = item;
return (
<div>
<Grid className="header-item">
<Grid.Column mobile={16} tablet={6} computer={8}>
<Image src={poster.url} alt={title} fluid />
<CarouselScreenshots title={title} screenshots={screenshots} />
</Grid.Column>
<Grid.Column mobile={16} tablet={10} computer={8}>
<Info item={item} />
</Grid.Column>
</Grid>
</div>
);
}
function Info(props) {
const { item } = props;
const { title, summary, price, discount, url } = item;
const [isFavorites, setIsFavorites] = useState(false);
const [reloadFavorite, setReloadFavorite] = useState(false);
const { auth, logout } = useAuth();
const { addProductCart } = useCart();
const [sizeItem, setSizeItem] = useState(null);
const [quantity, setQuantity] = useState(null);
useEffect(() => {
(async () => {
const response = await isFavoriteApi(auth.idUser, item.id, logout);
if (size(response) > 0) setIsFavorites(true);
else setIsFavorites(false);
})();
setReloadFavorite(false);
}, [item, reloadFavorite]);
const addFavorite = async () => {
if (auth) {
await addFavoriteApi(auth.idUser, item.id, logout);
setReloadFavorite(true);
}
};
const deleteFavorite = async () => {
if (auth) {
await deleteFavoriteApi(auth.idUser, item.id, logout);
setReloadFavorite(true);
}
};
const sizes = [
{
key: 'Small',
text: 'Small',
value: 'Small',
name: 'size'
},
{
key: 'Medium',
text: 'Medium',
value: 'Medium',
name: 'size'
},
{
key: 'Large',
text: 'Large',
value: 'Large',
name: 'size'
},
]
return (
<>
<div className="header-item__title">
{title}
</div>
<div className="header-item__buy">
<div className="header-item__buy-price">
{/* <p>Public price: ${price} </p> */}
<div className="header-item__buy-price-actions">
{discount && <div className="header-item__buy-price-actions"> <p>-{discount}% </p>
<p>${(price - Math.floor(price * discount) / 100).toFixed(2)}</p></div>}
{!discount && <p>${price}</p>}
</div>
<p className="subtitle">Size</p>
<Form>
<Form.Dropdown
placeholder='Select size'
fluid
selection
options={sizes}
/>
<p>Quantity</p>
<Form.Input placeholder='1' />
</Form>
</div>
<div className="header-item__buy-btn-container">
<Button
className="header-item__buy-btn-container__buy-btn"
type="submit"
onClick={() => addProductCart(url)}
>
Buy Now
</Button>
<div className="heart-container" >
<Icon
name={isFavorites ? "heart" : "heart outline"}
className={classNames({ like: isFavorites })}
link
onClick={isFavorites ? deleteFavorite : addFavorite}
/>
</div>
</div>
</div>
<div
className="header-item__summary"
dangerouslySetInnerHTML={{ __html: summary }}
/>
<div className="tabs" >
<TabsItem />
</div>
</>
);
}
This is what you looking for.
With a functional component you will need to import useState hook, and set 2 states like this:
const [size, setSize] = useState("small");
const [quantity, setQuantity] = useState(0);
Then follow the documentation in the link above. You should ultimatly have something like
<select value={size} onChange={(e) => changeSize(e)}>. And in your changeSize function, you should use setSize function to set the state.
I would like to get the text entered in the below input textarea created dynamically after the selection of persons from the dropdown boxes. Would like to get output into a json format:
Now it is getting value from the last displayed text area. Could someone please advise ?
Provide sample codesandbox link below
Expected output:
[
{name:"Bader", reason:"Good news, please add the some data"},
{name:"Crots", reason:"Great person"},
{name:"Dan", reason:"Simple look"}
]
App.js
import React, { useRef, useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { Link, useHistory } from "react-router-dom";
import Multiselect from "multiselect-react-dropdown";
const options = [
{ key: "Aaron", id: 1 },
{ key: "Bader", id: 2 },
{ key: "Crots", id: 3 },
{ key: "Dan", id: 4 },
{ key: "Elep", id: 5 },
{ key: "Pal", id: 6 },
{ key: "Quilt", id: 7 }
];
const App = () => {
const maxOptions = 3;
const [selectedOption, setSelectedOption] = useState([]);
const [nomRegister, setNomRegister] = useState([]);
const {
register,
handleSubmit,
watch,
formState: { errors }
} = useForm();
const handleTypeSelect = (e) => {
const copy = [...selectedOption];
copy.push(e);
setSelectedOption(copy);
};
const handleTypeRemove = (e) => {
const copy = [...selectedOption];
let index = copy.indexOf(e);
copy.splice(index, 1);
setSelectedOption(copy);
};
const sendNomination = () => {
console.log("Doesn't print all, what the heck: " + nomRegister);
};
return (
<div className="App">
<h1>Person selection</h1>
<div className="nomineeSelectBox">
<div id="dialog2" className="triangle_down1"></div>
<div className="arrowdown">
<Multiselect
onSelect={handleTypeSelect}
onRemove={handleTypeRemove}
options={selectedOption.length + 1 === maxOptions ? [] : options}
displayValue="key"
showCheckbox={true}
emptyRecordMsg={"Maximum nominees selected !"}
/>
</div>
</div>
<form onSubmit={handleSubmit(sendNomination)}>
<div className="nomineesSelectedList">
<h3>Selected Persons</h3>
{selectedOption.map((x, i) => (
<div key={i}>
<div className="row eachrecord">
<div className="column">
<label className="nomlabel">
{x[i].key} <b>>></b>
</label>
</div>
<input
required
type="textarea"
key={i}
id={i}
name={x[i].key}
className="nomineechoosed"
onChange={(e) => setNomRegister(e.target.value)}
/>
</div>
</div>
))}
<div className="row">
<div className="buttongroup">
<input id="Submit" type="submit" value="Submit" />
<input id="Cancel" type="button" value="Cancel" />
</div>
</div>
</div>
</form>
</div>
);
};
export default App;
Codesandbox link:
https://codesandbox.io/s/elastic-elbakyan-uqpzy?file=/src/App.js
After few modifications, I got a solution.
import React, { useRef, useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { Link, useHistory } from "react-router-dom";
import Multiselect from "multiselect-react-dropdown";
const options = [
{ key: "Aaron", id: 1 },
{ key: "Bader", id: 2 },
{ key: "Crots", id: 3 },
{ key: "Dan", id: 4 },
{ key: "Elep", id: 5 },
{ key: "Pal", id: 6 },
{ key: "Quilt", id: 7 }
];
const App = () => {
const maxOptions = 3;
const [selectedOption, setSelectedOption] = useState([]);
const [nomRegister, setNomRegister] = useState([{}]);
const {
register,
handleSubmit,
watch,
formState: { errors }
} = useForm();
// const onChange = (e) =>{
// e.persist();
// setNomRegister({ ...nomRegister, [e.target.id]: e.target.value });
// }
const handleTypeSelect = (e) => {
const copy = [...selectedOption];
copy.push(e);
setSelectedOption(copy);
};
const handleTypeRemove = (e) => {
const copy = [...selectedOption];
console.log(copy);
let index = copy.indexOf(e);
copy.splice(index, 1);
setSelectedOption(copy);
// immutating state (best practice)
const updateList = nomRegister.map((item) => {
return { ...item };
});
//delete the specific array case depends on the id
updateList.splice(index, 1);
setNomRegister(updateList);
};
const sendNomination = () => {
console.log(
"Doesn't print all, what the heck: " + JSON.stringify(nomRegister) // i did JSON.stringify just to see the console
);
};
const handleChange = (e, i) => {
const { name, value } = e.target;
// immutating state (best practice)
const updateList = nomRegister.map((item) => {
return { ...item };
});
//change the specific array case depends on the id
updateList[i] = { ...updateList[i], name: name, reason: value };
setNomRegister(updateList);
};
return (
<div className="App">
<h1>Person selection</h1>
<div className="nomineeSelectBox">
<div id="dialog2" className="triangle_down1"></div>
<div className="arrowdown">
<Multiselect
onSelect={handleTypeSelect}
onRemove={handleTypeRemove}
options={selectedOption.length + 1 === maxOptions ? [] : options}
displayValue="key"
showCheckbox={true}
emptyRecordMsg={"Maximum nominees selected !"}
/>
</div>
</div>
<form onSubmit={handleSubmit(sendNomination)}>
<div className="nomineesSelectedList">
<h3>Selected Persons</h3>
{selectedOption.map((x, i) => (
<div key={i}>
<div className="row eachrecord">
<div className="column">
<label className="nomlabel">
{x[i].key} <b>>></b>
</label>
</div>
<input
required
type="textarea"
key={i}
id={i}
name={x[i].key}
className="nomineechoosed"
onChange={(e) => handleChange(e, i)}
/>
</div>
</div>
))}
<div className="row">
<div className="buttongroup">
<input id="Submit" type="submit" value="Submit" />
<input id="Cancel" type="button" value="Cancel" />
</div>
</div>
</div>
</form>
</div>
);
};
export default App;
check Codesandbox
Not sure where I am going wrong here. editMedicine should be a function but it is not. When I click the edit medicine button, I get an error onSubmit. I know in other areas of my code I had some misspellings and capitalization issues, I am hoping this is the case here . I have been looking at this for so long that I cant quite spot whats going on.
import React, { Fragment, useState, useContext, useEffect } from "react";
import { GlobalContext } from "../context/GlobalState.js";
import { useHistory, Link } from "react-router-dom";
const Editmedicine = (route) => {
let history = useHistory();
const { medicines, editMedicine } = useContext(GlobalContext);
const [selectedUser, setSeletedUser] = useState({
id: null,
name: "",
directions: "",
});
const currentUserId = route.match.params.id;
useEffect(() => {
const medicineId = currentUserId;
const selectedUser = medicines.find(
(med) => med.id === parseInt(medicineId)
);
setSeletedUser(selectedUser);
}, []);
const onSubmit = (e) => {
e.preventDefault();
editMedicine(selectedUser);
history.push("/");
};
const handleOnChange = (userKey, value) =>
setSeletedUser({ ...selectedUser, [userKey]: value });
if (!selectedUser || !selectedUser.id) {
return <div>sdf</div>;
}
return (
<Fragment>
<div id="editContainer">
<form onSubmit={onSubmit}>
<div className="w-full mb-5">
<label
htmlFor="name"
>
Name of medicine
</label>
<input
value={selectedUser.name}
onChange={(e) => handleOnChange("name", e.target.value)}
type="text"
placeholder="Enter name"
/>
</div>
<div className="w-full mb-5">
<label
htmlFor="directions"
>
Directions
</label>
<input
value={selectedUser.directions}
onChange={(e) => handleOnChange("directions", e.target.value)}
type="text"
placeholder="Enter directions"
/>
</div>
<div className="flex items-center justify-between">
<button id="editMedicine">
Edit medicine
</button>
</div>
<div className="text-center mt-4 text-gray-500">
<Link to="/">Cancel</Link>
</div>
</form>
</div>
</Fragment>
);
};
export default Editmedicine;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
// here is the globalState file
import React, { createContext, useReducer } from "react";
import AppReducer from "./AppReducer";
//start by setting the initial state
const initialState = {
medicines: [
{
id: 1,
name: "Daily Multivitamin",
directions: "Take once a day with 2 glasses of water"
},
{
id: 2,
name: "Herbal capsule",
directions: "Take once a day with food"
},
{
id: 3,
name: "Tincture",
directions: "1 drop a day, 3x a day."
}
]
};
//create context
export const GlobalContext = createContext(initialState);
//provider component
export const GlobalProvider = ({ children }) => {
const [state, dispatch] = useReducer(AppReducer, initialState);
function removeMedicine(id) {
dispatch({
type: "REMOVE_MEDICINE",
payload: id
});
}
//this might have to be ADD_MEDICINE or S instead
function addMedicine(medicines) {
dispatch({
type: "ADD_MEDICINE",
payload: medicines
});
}
function editMedicine(medicines) {
dispatch({
type: "EDIT_MEDICINE",
payload: medicines
});
}
return (
<GlobalContext.Provider
value={{
medicines: state.medicines,
removeMedicine,
addMedicine,
editMedicine
}}
>
{children}
</GlobalContext.Provider>
);
};
I need to prevent the user from being able to add names that already exist in the person list but I'm not sure where should I add it and also what method is better to use .includes or indexOf? I want issue a warning with the alert command when such an action is attempted. Any help would be much appropriated!
import React, { useState } from 'react'
const App = () => {
const [ persons, setPersons ] = useState([ { name: 'Arto Hellas' }])
const [ newName, setNewName ] = useState('')
const addName = (event) => {
event.preventDefault()
const nameObject = {
name: newName,
}
setPersons([...persons,nameObject])
}
const handleNameChange = (event) => {
setNewName(event.target.value)
}
return (
<div>
<h2>Phonebook</h2>
<form onSubmit={addName} >
<div>
name: <input value={newName} onChange={handleNameChange} />
</div>
<div>
<button type="submit">add</button>
</div>
</form>
<h2>Numbers</h2>
{persons.map(person => (
<p key={person.name}>{person.name}</p>
))}
</div>
)
}
export default App
You need to do something in the following place:
const addName = (event) => {
event.preventDefault();
const nameObject = {
name: newName
};
setPersons([...persons, nameObject]);
};
Use .find() on the persons array to find the particular name already existing and add the condition before setPersons is executed.
if (persons.find(p => p.name === newName)) {
window.alert("Name already exists!");
return false;
}
A code like above will work.
import React, { useState } from "react";
const App = () => {
const [persons, setPersons] = useState([{ name: "Arto Hellas" }]);
const [newName, setNewName] = useState("");
const addName = (event) => {
event.preventDefault();
if (persons.find((p) => p.name === newName)) {
window.alert("Name already exists!");
return false;
}
const nameObject = {
name: newName
};
setPersons([...persons, nameObject]);
};
const handleNameChange = (event) => {
setNewName(event.target.value);
};
return (
<div>
<h2>Phonebook</h2>
<form onSubmit={addName}>
<div>
name: <input value={newName} onChange={handleNameChange} />
</div>
<div>
<button type="submit">add</button>
</div>
</form>
<h2>Numbers</h2>
{persons.map((person) => (
<p key={person.name}>{person.name}</p>
))}
</div>
);
};
export default App;
Demo: https://codesandbox.io/s/nervous-poitras-i3stw?file=/src/App.js:0-958
The above code shows an ugly Error Alert using the normal window alert. If you want a better error like this:
You can use the following code, by setting a state:
import React, { useState } from "react";
import "./styles.css";
const App = () => {
const [persons, setPersons] = useState([{ name: "Arto Hellas" }]);
const [newName, setNewName] = useState("");
const [error, setError] = useState(false);
const addName = (event) => {
event.preventDefault();
if (persons.find((p) => p.name === newName)) {
setError(true);
return false;
}
const nameObject = {
name: newName
};
setPersons([...persons, nameObject]);
};
const handleNameChange = (event) => {
setNewName(event.target.value);
};
return (
<div>
<h2>Phonebook</h2>
<form onSubmit={addName}>
{error && <p className="error">User already exists.</p>}
<div>
name: <input value={newName} onChange={handleNameChange} />
</div>
<div>
<button type="submit">add</button>
</div>
</form>
<h2>Numbers</h2>
{persons.map((person) => (
<p key={person.name}>{person.name}</p>
))}
</div>
);
};
export default App;
And here's our style.css:
.error {
background-color: red;
color: #fff;
padding: 5px;
}
Demo: https://codesandbox.io/s/vibrant-tree-wsou2?file=/src/App.js
First add field to check name exists or not:
const nameExists = React.useMemo(() => {
return persons.some(item => item.name === newName);
}, [newName, persons])
Then disable button and show message if name exists:
<div>
{nameExists && <p>Name {newName} already exists!</p>}
<button type="submit" disabled={nameExists} >add</button>
</div>
Also, make sure you clear name when you add new name:
const addName = (event) => {
...
setNewName('')
}
const App = () => {
const [ persons, setPersons ] = React.useState([ { name: 'Arto Hellas' }])
const [ newName, setNewName ] = React.useState('')
const addName = (event) => {
event.preventDefault()
const nameObject = {
name: newName,
}
setPersons([...persons,nameObject]);
setNewName('')
}
const handleNameChange = (event) => {
setNewName(event.target.value)
}
const nameExists = React.useMemo(() => {
return persons.some(item => item.name === newName);
}, [newName, persons])
return (
<div>
<h2>Phonebook</h2>
<form onSubmit={addName} >
<div>
name: <input value={newName} onChange={handleNameChange} />
</div>
<div>
{nameExists && <p>Name {newName} already exists!</p>}
<button type="submit" disabled={nameExists} >add</button>
</div>
</form>
<h2>Numbers</h2>
{persons.map(person => (
<p key={person.name}>{person.name}</p>
))}
</div>
)
}
ReactDOM.render(<App />, document.getElementById('root'))
<script crossorigin src="https://unpkg.com/react#17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#17/umd/react-dom.development.js"></script>
<div id="root"></div>
You can use the find method to search for a person with the newName. Please check the below code-snippet:
const addName = (event) => {
event.preventDefault()
const nameObject = {
name: newName,
}
let personAlreadyExists = persons.find(person => person.name === newName);
if (personAlreadyExists) {
alert('Person with that name already exists');
// any other operations (like clearing user input in the form, etc..)
}
else {
setPersons([...persons, nameObject])
}
}
Code-Sandbox