I am using the react-select dropdown what my task is I need to clear the selected field in onClick of reset button mean like if I select on the name in the drop-down it will visible in what I selected so I need to clear the selected field or after clear placeholder filed will visible then again am I am able to select field
const [data, setData] = React.useState([]);
const [value, setValue]= React.useState('')
const handleSelectChange = (object, action) => {
let name = action.name;
let value = object;
setFormData((prevFormData) => ({
...prevFormData,
[name]: object,
}));
};
const handleSelectChangeL = (object, action) => {
setIndex(data[object.id]);
setUserlevel(null);
let name = action.name;
let value = object.value;
setFormData((prevFormData) => ({
...prevFormData,
[name]: value,
}));
};
const reset = () => {
setValue('')
};
<Select
className="drop-down"
options={screenType}
name="screen"
value={value}
onChange={handleSelectChange}
placeholder="Screen Type"
theme={(theme) => ({
...theme,
colors: {
...theme.colors,
text: "black",
primary25: "#d6fdf7",
primary: "#0bb7a7",
primary50: "#d6fdf7",
},
})}
></Select>
<Select
className="drop-down"
options={data?.map((data, index) => ({
value: data.username,
label: data.username,
id: index,
}))}
name="user"
value={data.username}
onChange={handleSelectChangeL}
placeholder="User Name"
theme={(theme) => ({
...theme,
colors: {
...theme.colors,
text: "black",
primary25: "#d6fdf7",
primary: "#0bb7a7",
primary50: "#d6fdf7",
},
})}
></Select>
<button
className="dash-button-1"
type="submit"
variant="contained"
onClick={reset}
>
Reset
</button>
You will have to toggle the state of value prop in the <Select>tag. You may define a state like const [value, setValue]= useState('') and change its value based on the onChange function.
Your reset function could be like this:
const reset = () => {
setValue('')
};
This will again reset the value of the Select Tag.
Update your Select value field with the state value like below,
import { useEffect, useState } from "react";
import "./styles.css";
import Select from "react-select";
const data = [
{
username: "jerry"
},
{
username: "Tim"
},
{
username: "Ravi"
}
];
export default function App() {
const [value, setValue] = useState("");
const reset = () => {
setValue("");
};
const handleSelectChange = (selected) => {
setValue(selected);
};
return (
<div>
<Select
className="drop-down"
options={data?.map((data, index) => ({
value: data.username,
label: data.username,
id: index
}))}
name="user"
value={value} // <---- CHANGE HERE
onChange={handleSelectChange}
placeholder="User Name"
theme={(theme) => ({
...theme,
colors: {
...theme.colors,
text: "black",
primary25: "#d6fdf7",
primary: "#0bb7a7",
primary50: "#d6fdf7"
}
})}
></Select>
<button
className="dash-button-1"
type="submit"
variant="contained"
onClick={reset}
>
Reset
</button>
</div>
);
}
codesandbox - https://codesandbox.io/s/nervous-chaplygin-y5lqx?file=/src/App.js:0-1181
If you will use useEffect then i think your issue will be resolved.
useEffect(()=>{
},[value])
//i will suggest to store the name in value and then it will work (setValue(data.username))
Related
Feeding the react-select component the selected state to the value prop, makes it unable to select anything at all? I'm trying to feed the value-prop with the selected state so that i can reset react-select via setState. What am i doing wrong here?
Select Component with isMulti option:
import SelectForm from "react-select";
const Select = (props) => {
const options = props.options.map((option) => ({
value: option,
label: option.toLowerCase(),
}));
const costumStyles = {
container: (baseStyles) => ({ ...baseStyles, width: "100%" }),
control: (baseStyles) => ({
...baseStyles,
backgroundColor: "transparent",
borderStyle: "none",
borderRadius: "15px",
marginTop: "3px",
}),
singleValue: (baseStyles) => ({ ...baseStyles, color: "white" }),
};
const handleChange = (event) => {
props.onChangeOption(event);
};
return (
<div>
{props.isMulti ? (
<SelectForm
options={options}
onChange={handleChange}
styles={costumStyles}
placeholder={props.placeholder}
value={props.value}
isMulti
/>
) : (
<SelectForm
options={options}
onChange={handleChange}
styles={costumStyles}
placeholder={props.placeholder}
value={props.value}
/>
)}
</div>
);
};
export default Select;
The parent component which uses the Select component:
import React, { useState } from "react";
import Select from "../../input/Select";
const CreateJobPage3 = (props) => {
const [department, setDepartment] = useState();
const [subDepartment, setSubDepartment] = useState([]);
const departments = [jobDepartment1, jobDepartment2, jobDepartment3];
const subDepartments = [jobSubDepartment1, jobSubDepartment2, jobSubDepartment3];
const departmentHandler = (props) => {
setDepartment(props.value);
setSubDepartment([]);
};
const subDepartmentHandler = (props) => {
setSubDepartment(props.map((item) => item.value));
};
return (
<>
<Select
placeholder="Choose Department"
options={departments}
onChangeOption={departmentHandler}
value={department || ""}
/>
<Select
placeholder="Choose Sub-Departments"
options={subDepartments}
onChangeOption={subDepartmentHandler}
isMulti={true}
value={subDepartment || ""}
/>
</>
);
};
export default CreateJobPage3;
According to the docs of react-select they're expecting complete option to be passed in value array.
Say for example, we have options like
const options=[
{ value: 'blue', label: 'Blue', color: '#0052CC', isDisabled: true },
{ value: 'red', label: 'Red', color: '#0052CC', isDisabled: true }
];
then we have to pass value as,
value={[{ value: 'blue', label: 'Blue', color: '#0052CC', isDisabled: true }]}
Refer this example: https://codesandbox.io/s/17g0yy?module=/example.tsx
Try this,
const departmentHandler = (props) => {
setDepartment(props);
setSubDepartment([]);
};
const subDepartmentHandler = (props) => {
setSubDepartment(props);
};
I need to render plenty of inputs for every name of the array, but the problem is creating dynamically useState const and onChange handler for every rendered input.
I try to create handleChange key for every item in an array and pass it to input onChange but got the "String Instead Fuction" error. How to resolve the problem in another way and also avoid code duplication?
export const myArr = [
{ name: "Crist", data: "crist", color: "lightblue", handleChange: "cristHandleChange"},
{ name: "Ruby", data: "ruby", color: "lightpink", handleChange: "rubyHandleChange"},
{ name: "Diamond", data: "diamond", color: "white", handleChange: "diamondHandleChange"},
];
export const myComponent = () => {
const [cristQuantity, setCristQuantity] = useState(0);
const [rubyQuantity, setRubyQuantity] = useState(0);
const [diamondQuantity, setDiamondQuantity] = useState(0);
function cristHandleChange(event) {
setCristQuantity(event.target.value);
}
function rubyHandleChange(event) {
setRubyQuantity(event.target.value);
}
function diamondHandleChange(event) {
setDiamondQuantity(event.target.value);
}
return (
<>
{myArr
? myArr.map((item, index) => (
<div className="main-inputs__wrapper" key={`item${index}`}>
<label htmlFor={item.data}>{item.name}</label>
<input
type="number"
name={item.data}
style={{ background: item.color }}
onChange={item.handleChange} //???
/>
</div>
))
: null}
</>
);
};
You should create one handler for all inputs, and save values in a object with a key as item.data. Such way: {crist: 1, ruby: 3, diamond: 5}
export const myArr = [
{
name: "Crist",
data: "crist",
color: "lightblue"
},
{
name: "Ruby",
data: "ruby",
color: "lightpink"
},
{
name: "Diamond",
data: "diamond",
color: "white"
}
];
export function MyComponent() {
// Lazy initial state
// https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
const [quantities, setQuantities] = useState(() =>
myArr.reduce((initialQuantities, item) => {
initialQuantities[item.data] = 0;
return initialQuantities;
}, {})
);
// common handler for every onChange with computed property name
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#computed_property_names
const handleChange = (event) => {
setQuantities((prevQuantities) => ({
...prevQuantities,
[event.target.name]: event.target.value
}));
};
return (
<>
{Array.isArray(myArr)
? myArr.map((item, index) => (
<div className="main-inputs__wrapper" key={`item${index}`}>
<label htmlFor={item.data}>{item.name}</label>
<input
type="number"
name={item.data}
style={{ background: item.color }}
onChange={handleChange}
value={quantities[item.data] || ""}
/>
</div>
))
: null}
</>
);
}
I haven't actually tested this but this is something I would do which will get you on the way.
export const myArr = [
{
name: `Crist`,
data: `crist`,
color: `lightblue`,
handleChange: `cristHandleChange`,
},
{
name: `Ruby`,
data: `ruby`,
color: `lightpink`,
handleChange: `rubyHandleChange`,
},
{
name: `Diamond`,
data: `diamond`,
color: `white`,
handleChange: `diamondHandleChange`,
},
]
export const myComponent = () => {
const [quantities, setQuantities] = useState({
crist: 0,
ruby: 0,
diamond: 0,
})
const onChangeHandler = ({ name, value }) => {
setQuantities((prevState) => ({ ...prevState, [name]: value }))
}
return (
<>
{myArr.length > 0
? myArr.map(({ data, name, color }, index) => {
// if you need to do an update to push more items to the object for any dynamic reason
if (!quantities.name)
setQuantities((prevState) => ({ ...prevState, [name]: 0 }))
return (
<div className="main-inputs__wrapper" key={`item${index}`}>
<label htmlFor={data}>{name}</label>
<input
type="number"
name={name}
value={quantities.name}
style={{ background: color }}
onChange={(e) =>
onChangeHandler({ name, value: e.currentTarget.value })
}
/>
</div>
)
})
: null}
</>
)
}
You're passing a string (not a function) to onChange which is causing that problem.
To fix it, you can wrap all functions into another object
const onChangeFunctions = {
cristHandleChange: (event) => {
setCristQuantity(event.target.value);
},
rubyHandleChange: (event) => {
setRubyQuantity(event.target.value);
},
diamondHandleChange: (event) => {
setDiamondQuantity(event.target.value);
},
};
and call onChangeFunctions[item.handleChange] like below
export const myArr = [
{
name: "Crist",
data: "crist",
color: "lightblue",
handleChange: "cristHandleChange",
},
{
name: "Ruby",
data: "ruby",
color: "lightpink",
handleChange: "rubyHandleChange",
},
{
name: "Diamond",
data: "diamond",
color: "white",
handleChange: "diamondHandleChange",
},
];
export const myComponent = () => {
const [cristQuantity, setCristQuantity] = useState(0);
const [rubyQuantity, setRubyQuantity] = useState(0);
const [diamondQuantity, setDiamondQuantity] = useState(0);
const onChangeFunctions = {
cristHandleChange: (event) => {
setCristQuantity(event.target.value);
},
rubyHandleChange: (event) => {
setRubyQuantity(event.target.value);
},
diamondHandleChange: (event) => {
setDiamondQuantity(event.target.value);
},
};
return (
<>
{myArr
? myArr.map((item, index) => (
<div className="main-inputs__wrapper" key={`item${index}`}>
<label htmlFor={item.data}>{item.name}</label>
<input
type="number"
name={item.data}
style={{ background: item.color }}
onChange={onChangeFunctions[item.handleChange]}
/>
</div>
))
: null}
</>
);
};
Let me start by saying that you might want to use a library like React Hook Form for this, although, if this is the only form and you don't need all the fancy features (or additional bundle size), you can do it like this as well.
The first step is to store your form data in an Object. After this change, you can use a single useState({}) to store and read your form data and drastically simplifies your handlers.
For example:
export const myArr = [
{ name: "Crist", data: "crist", color: "lightblue"},
{ name: "Ruby", data: "ruby", color: "lightpink"},
{ name: "Diamond", data: "diamond", color: "white"},
];
// generate Object with data and initialValue or empty string
// e.g. `{ 'crist': '', 'ruby': '', 'diamond': '' }`
const getInitialFormValues = (arr) => Object.fromEntries(
arr.map(({ data, initialValue }) => [data, initialValue || ''])
);
export const MyComponent = () => {
const [formValues, setFormValues] = useState(getInitialFormValues(myArr));
function handleChange(event) {
// update the changed form value
setFormValues(current => ({
...current, // other form values
[event.target.name]: event.target.value // updated value
}));
}
return (
<>
{myArr
? myArr.map((item, index) => (
<div className="main-inputs__wrapper" key={`item${index}`}>
<label htmlFor={item.data}>{item.name}</label>
<input
type="number"
name={item.data}
style={{ background: item.color }}
onChange={handleChange}
value={formValues[item.data]}
/>
</div>
))
: null}
</>
);
};
I'm trying to create a custom hook that'll can be used in any form but i have a problem which i am not sure of what it is. whenever i start typing into the fields it loses focus, to type into it again you'd have to click into it and it goes on like that. this isn't good and i would appreciate it if anyone can help me solve this error.
useForm.js
import { useState } from "react";
const useForm = () => {
const [values, setValues] = useState({
// contact form
});
const [errors, seterrors] = useState({});
const handleChange = (e) => {
const { name, value } = e.target;
setValues({
...values,
[name]: value
});
// console.log(name, value);
};
const validate = (data) => {};
const handleSubmit = (e) => {
e.preventDefault();
// console.log(e);
};
// console.log(values);
return {
handleChange,
values,
handleSubmit
};
};
export default useForm;
Form.js
import InputGroup from "./InputGroup";
import useForm from "./useForm";
const Form = () => {
const fields = [
{
label: "First Name",
className: "input-group",
name: "firstName",
placeholder: "John",
type: "text"
},
{
label: "Last Name",
className: "input-group",
name: "lastName",
placeholder: "Doe",
type: "text"
},
{
label: "Email",
className: "input-group",
name: "email",
placeholder: "JohnDoe#example.com",
type: "email"
},
{
label: "Phone Number",
className: "input-group",
name: "Phone",
placeholder: "+234 (0)81 234 5678",
type: "text"
// pattern: "/^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-s./0-9]*$/g"
},
{
label: "Comments",
className: "input-group",
name: "comment",
placeholder: "Message",
type: "textarea"
}
];
const { values, handleChange, handleSubmit } = useForm();
//funtion to generate id based on fields lenght
const id = () => {
const head = Date.now.toString(36);
const tail = Math.random().toString(36).substr(2);
return head + tail;
};
console.log(id);
return (
<form onSubmit={handleSubmit}>
{fields.map((field) => (
<InputGroup
key={id}
value={values}
onChange={handleChange}
{...field}
/>
))}
<button>submit</button>
</form>
);
};
export default Form;
Input
const Input = ({ ...props }) => {
return <input {...props} />;
};
export default Input;
You are not using your id function properly, you are only referring to it, not invoking it, change -
<InputGroup
key={id}
to
<InputGroup
key={id()}
or better still, a better name, using a verb would have highlighted the problem easier, as it now looks like a function and not a variable
<InputGroup
key={buildId()}
or whatever, but better still, you should use a static unique value for the key (i.e unique but would not change between renders, so using timestamps is a bad idea), so you could add a unique id to each field and use it -
const fields = [
{
id: <some unique ID>, <!---- here
label: "First Name",
className: "input-group",
name: "firstName",
placeholder: "John",
type: "text"
}
...
]
...
<InputGroup
key={field.id}
Below is the code where I am trying to select value from dropdown.
handleChange is not working, when I select the value from dropdown it's not getting updated with selected value from dropdown. It's getting vanished(blank).
Dropdown values are getting populated when I select it's not catching the new selected value.
Can someone help me on this like what I am missing here?
export const FormikSelectField = ({ label, ...props }) => {
const [field, meta] = useField(props);
const [isFocused, setOnFocus] = useState(false);
const handleChange = (value) => {
// this is going to call setFieldValue and manually update values.topcis
console.log('Value in handlechange..', value ,'and', props.name);
props.onChange(props.name, value.value);
};
const handleFocus = () => {
setOnFocus(true);
};
const handleBlur = (e) => {
// this is going to call setFieldTouched and manually update touched.topcis
setOnFocus(false);
props.onBlur(props.name, true);
field.onBlur(e);
};
return (
<>
<label htmlFor={props.labelName}>{props.labelName} </label>
<Select
id={props.labelName}
options={props.options}
isMulti={false}
onChange={handleChange}
onBlur={(e) => handleBlur(e)}
placeholder='Select an option'
onFocus={handleFocus}
value={props.value}
/>
{meta.touched && meta.error && !isFocused ? (
<div className="error">{meta.error}</div>
) : null}
</>
);
};
formikInitialValues = () => {
return {
Name: [{
title: '',
value: '',
}]
};
};
YupValidationSchema = () => {
return Yup.object({
Name: Yup.array()
.of(
Yup.object().shape({
title: Yup.string().required(),
value: Yup.string().required(),
})
)
.required("Please select an option")
.nullable()
});
};
<FormikSelectField
value={this.state.selectNameOption}
onChange={this.handleNameChange}
onBlur={this.handleNameChangeBlur}
error={formik.errors.Name}
options={this.state.NameOptions}
touched={formik.touched.Name}
name="Name"
labelName="Name"
/>
You should avoid mixing the state when using Formik. Formik will take care of the state for you.
import { Formik, Form, useField, ErrorMessage } from "formik";
import * as Yup from "yup";
import Select from "react-select";
const iceCreamOptions = [
{ value: "chocolate", label: "Chocolate" },
{ value: "strawberry", label: "Strawberry" },
{ value: "vanilla", label: "Vanilla" }
];
const FormSelect = ({ name, options }) => {
const [field, meta, helpers] = useField(name);
return (
<>
<Select
name={name}
value={field.value}
onChange={(value) => helpers.setValue(value)}
options={options}
onBlur={() => helpers.setTouched(true)}
/>
<ErrorMessage name={name} />
</>
);
};
const initialValues = {
icecream: null
};
const validationSchema = Yup.object().shape({
icecream: Yup.object()
.shape({
value: Yup.string(),
label: Yup.string()
})
.required("Please select a value")
.nullable()
});
export default function App() {
return (
<Formik
initialValues={initialValues}
onSubmit={(values) => console.log(values)}
validationSchema={validationSchema}
>
{(props) => {
return (
<Form>
<pre>{JSON.stringify(props, undefined, 2)}</pre>
<FormSelect name="icecream" options={iceCreamOptions} />
</Form>
);
}}
</Formik>
);
}
Example Working Sandbox
Write this code
onChange={(e:React.ChangeEvent<HTMLInputElement>)=> setFieldValue("title",e.target.value)}
or
onChange={(e)=> setFieldValue("title",e.target.value)}
I am getting an array or an object from the backend what my task is to set the first index mean [0] to set in default value but when I set I am getting undefined you can see in code userL taking my array of an object but when I print userle it's showing label: undefined value: undefined or when I print userL I'm getting my array of object list
const [userL, setUserL] = useState([]);
useEffect(() => {
axios
.get(`${DJANGO_SERVER_ADDRESS}/auth/analyst/`)
.then((res) => {
setUserL(res.data);
})
.then(
(result) => {
},
(error) => {
}
);
}, []);
console.log("ena1", userL);
const [userle, setUserle] = useState(
{ value: userL[0].username,
label: userL[0].username,
});
console.log("nnnnnnnnnuuuu",userle)
console.log('nnnnnnnnnnn',userL[0])
const handleSelectChangeL = (object, action) => {
setIndex(userL[object.id]);
setUserlevel(null);
console.log("select check", object.label, action.name, index);
let name = action.name;
let value = object.value;
setFormData((prevFormData) => ({
...prevFormData,
[name]: value,
}));
};
<Col lg={2}>
<label for="user">
<header>User</header>
</label>
<Select
options={userL.map((data, index) => ({
value: data.username,
label: data.username,
id: index,
}))}
styles={styles2}
value={userle}
name="user"
onChange={handleSelectChangeL}
placeholder="User"
theme={(theme) => ({
...theme,
colors: {
...theme.colors,
text: "black",
primary25: "#d6fdf7",
primary: "#0bb7a7",
primary50: "#d6fdf7",
},
})}
></Select>
</Col>
If you want to set the state of the userle from the first element of the data, do it this way.
const [userle, setUserle] = useState()
const [userL, setUserL] = useState([]);
useEffect(() => {
axios
.get(`${DJANGO_SERVER_ADDRESS}/auth/analyst/`)
.then((res) => {
setUserL(res.data);
setUserle(res.data[0]?.username);
})
.then(
(result) => {
},
(error) => {
}
);
}, []);
EDIT
To also update the userle state onChange of the dropdown list, add setUserle() under your handleSelectChangeL function.
JS
const handleSelectChangeL = (object, action) => {
setIndex(userL[object.id]);
setUserlevel(null);
console.log("select check", object.label, action.name, index);
let name = action.name;
let value = object.value;
setUserle(value); // Add this line
setFormData((prevFormData) => ({
...prevFormData,
[name]: value,
}));
};
if you using useState, You cannot get expected result of updated state in same function, but if want to print the result, you must write useEffect with dependency userle state or maybel you can console it above "return" statement in functional Commponent