Formik: How to set initial values for fieldArray - reactjs

I am using Formik FieldArray in a Form Each row has 3 dropdowns. I'm not sure how to set the initial values in the dropdowns. For example, if I have the array
[
{
mainField: "one",
operation: "one",
value: ["one"]
},
{
mainField: "two",
operation: "two",
value: ["two","2"]
},
{
mainField: "three",
operation: "three",
value: ["3"]
}
]
then, I want the Form to be loaded with these values in 3 rows initially.
import React, { useState } from "react";
import { Button, Dropdown, Form, Grid, Icon } from "semantic-ui-react";
import { Formik, FieldArray } from "formik";
import "./styles.css";
const mainField = [
{ key: "fruit", text: "fruit", value: "fruit" },
{ key: "color", text: "color", value: "color" },
{ key: "taste", text: "taste", value: "taste" }
];
const operation = [
{ key: "is ", text: "is ", value: "is " },
{ key: "is not ", text: "is not ", value: "is not " }
];
const options = [
{ key: "apple", text: "apple", value: "apple" },
{ key: "yellow", text: "yellow", value: "yellow" },
{ key: "sweet", text: "sweet", value: "sweet" }
];
const initialValues = [
{
mainField: "one",
operation: "one",
value: ["one"]
},
{
mainField: "two",
operation: "two",
value: ["two","2"]
},
{
mainField: "three",
operation: "three",
value: ["3"]
}
]
const DropDownWithHooks = () => {
const [dropDownOptions, setDropDownOptions] = useState(options);
const handleAddition = (e, { value }) => {
setDropDownOptions((prevOptions) => [
{ text: value, value },
...prevOptions
]);
};
return (
<Formik
initialValues={{ rows: initialValues }}
onSubmit={(values) => {
// transform the rows to add the condition key for each row object
const output = values.rows.map((row, index) => {
if (index === 0) {
return { ...row, condition: "if" };
} else {
return { ...row, condition: "and" };
}
});
console.log(output);
}}
>
{({ handleSubmit, values, setFieldValue }) => (
<Form onSubmit={handleSubmit} className={"rulesetForm"}>
<pre>{JSON.stringify(values, null, 2)}</pre>
<FieldArray
name="rows"
render={({ push, remove }) => {
return (
values.rows.length > 0 &&
values.rows.map((row, index) => {
return (
<Grid key={`mainfield-operation-value-${index}`}>
<Grid.Row className={"rulesetGrid fluid"}>
{index === 0 ? (
<p className="condition"> If</p>
) : (
<p className="condition"> And</p>
)}
<Dropdown
name={`rows.${index}.mainField`}
className={"dropdown fieldDropdown"}
widths={2}
placeholder="Fruit"
fluid
selection
options={mainField}
value={row.mainField}
onChange={(e, { value }) =>
setFieldValue(`rows.${index}.mainField`, value)
}
/>
<Dropdown
name={`rows.${index}.operation`}
className={"dropdown operationDropdown"}
widths={2}
placeholder="Operation"
fluid
selection
options={operation}
value={row.operation}
onChange={(e, { value }) =>
setFieldValue(`rows.${index}.operation`, value)
}
/>
<Dropdown
name={`rows.${index}.value`}
className={"dropdown valueDropdown"}
widths={1}
placeholder="Value"
fluid
search
allowAdditions
selection
multiple
options={dropDownOptions}
value={row.value}
onAddItem={handleAddition}
onChange={(e, { value }) =>
setFieldValue(`rows.${index}.value`, value)
}
/>
{values.rows.length - 1 === index && (
<Icon
className={" plus icon plusIcon"}
onClick={() => push(initialValues)}
/>
)}
{values.rows.length !== 1 && (
<Icon
className={"minus crossIcon"}
onClick={() => remove(index)}
/>
)}
</Grid.Row>
</Grid>
);
})
);
}}
/>
<div>
<div style={{ marginTop: "1rem" }}>
<Button
floated="right"
type="submit"
variant="contained"
primary={true}
>
Submit
</Button>
</div>
</div>
</Form>
)}
</Formik>
);
};
export default DropDownWithHooks;
With this code, I am not getting these values initially in the dropdowns. Please help Any help is greatly appreciated, Thanks in advance
Working Sandbox here

Related

Browser Error for React Component Seperation

im having a slight problem with my react code, im trying to create a simple react appplication that has seperated components, as im still currently learning. Can someone look at this code and let me know whats going wrong? My dropdown component when added makes the browser load forever, so its something to do with that component, as when removed from app.js, it loads fine
import * as React from "react";
function Dropdown() {
const [food, setFood] = React.useState("fruit");
const [drink, setDrink] = React.useState("water");
const handleFoodChange = (event) => {
setFood(event.target.value);
};
const handleDrinkChange = (event) => {
setDrink(event.target.value);
};
return (
<div>
<Dropdown
label="What do we eat?"
options={[
{ label: "Fruit", value: "fruit" },
{ label: "Vegetable", value: "vegetable" },
{ label: "Meat", value: "meat" },
]}
value={food}
onChange={handleFoodChange}
/>
<Dropdown
label="What do we drink?"
options={[
{ label: "Water", value: "water" },
{ label: "Beer", value: "beer" },
{ label: "Wine", value: "wine" },
]}
value={drink}
onChange={handleDrinkChange}
/>
<p>We eat {food}!</p>
<p>We drink {drink}!</p>
</div>
);
}
export default Dropdown;
Below is how its being imported
import "./App.css";
import Checkbox from "./components/Checkbox";
import Dropdown from "./components/Dropdown";
function App() {
return (
<div>
<Checkbox />
<Dropdown />
<h1>test</h1>
</div>
);
}
export default App;
This is happening because you are importing Dropdown inside Dropdown component.
I updated your code to show you another way to create a Dropdown.
function DropdownContainer() {
const [food, setFood] = React.useState("fruit");
const [drink, setDrink] = React.useState("water");
const handleFoodChange = (event) => {
setFood(event.target.value);
};
const handleDrinkChange = (event) => {
setDrink(event.target.value);
};
return (
<div>
<Dropdown
label="What do we eat?"
selectedOption={food}
options={[
{ label: "Fruit", value: "fruit" },
{ label: "Vegetable", value: "vegetable" },
{ label: "Meat", value: "meat" },
]}
onHandleChange={handleFoodChange}
/>
<Dropdown
label="What do we drink?"
selectedOption={drink}
options={[
{ label: "Water", value: "water" },
{ label: "Beer", value: "beer" },
{ label: "Wine", value: "wine" },
]}
onHandleChange={handleDrinkChange}
/>
<p>We eat {food}!</p>
<p>We drink {drink}!</p>
</div>
);
}
function Dropdown({ selectedOption = "", label = "", options = [], onHandleChange }) {
return (
<select
label={label}
onChange={onHandleChange}
>
{options.map(opt => <option selected={selectedOption === opt.value} value={opt.value}>{opt.label}</option>)}
</ select>
);
}
export function App(props) {
return (
<DropdownContainer />
);
}
Why do you put <Dropdown ...> inside Dropdown function? It causes recursive call and results in infinite loading.
You should use <select ..> like below.
<select>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option selected value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>

How do I keep focus on my react input field once the onchange fires?

Newer to React. I have this column in a ReactTable which has an input textbox. I understand that changing the state is re-rending the form just not sure how to prevent that. Appreciate any guidance!
<ReactTable
key={googlecampaigndata?.length}
data={googlecampaigndata}
loading={googlecampaignloading}
sortable={false}
filterable={false}
columns={[
{
Header: "Account Name",
accessor: "customer_name"
},
{
Header: "Campaign Name",
accessor: "campaign_name"
},
{
Header: "Campaign Type",
accessor: "campaign_type"
},
{
Header: "Status",
accessor: "status"
},
{
Header: "Monthly Budget",
accessor: "monthly_budget"
},
{
Header: "Update Monthly Budget",
accessor: "update_monthly_budget",
Cell: ({ original }) => {
return (
<form
onSubmit={e => {
e.preventDefault();
if(submissionData !== {} && submitGoogleCampaignMonthlyBudgetForm()){
refetch();
}
}
}
>
<input
id={`monthly_budget${original.id}`}
type="text"
maxLength="12"
size="8"
style={{ float: "left" }}
onChange = {updateFieldHandler("monthly_budget", original.id)}
inputprops={{
type: "string",
required: true,
value: original['monthly_budget'] ? original['monthly_budget'] : ""
}}
/><Button
color="primary"
type="submit"
style={{ float: "right" }}
>
Submit
</Button>
</form>
);
},
},
{
Header: "Cycle Start Date",
accessor: "date"
}
]}
defaultPageSize={Math.min(pageSize, googlecampaigndata?.length || 2)}
showPaginationTop
showPaginationBottom={false}
onPageSizeChange={ps => setPageSize(ps)}
className="-striped -highlight"
/>
#EDIT
I tried returning my input field from outside of MyAccounts but I'm still losing focus on the input when typing. More of my updated code below.
import React, { useState, useContext, useEffect } from "react";
import { useQuery, useMutation } from "#apollo/react-hooks";
import { intersection, omit } from "lodash";
// #material-ui/core components
import { makeStyles } from "#material-ui/core/styles";
// #material-ui/icons
import Assignment from "#material-ui/icons/Assignment";
// core components
import GridContainer from "components/Grid/GridContainer";
import GridItem from "components/Grid/GridItem";
import Card from "components/Card/Card";
import CardBody from "components/Card/CardBody";
import CardIcon from "components/Card/CardIcon";
import CardHeader from "components/Card/CardHeader";
import ReactTable from "components/CustomReactTable";
import Button from "components/CustomButtons/Button";
import { cardTitle } from "assets/jss/material-dashboard-pro-react";
import { SUBMIT_GOOGLE_CAMPAIGN_MONTHLY_BUDGET_FORM } from "queries/formSubmission";
import { LIST_BUDGETS } from "queries/budget";
import { GET_GOOGLE_CAMPAIGNS } from "queries/budget";
import { Context } from "redux/store";
const styles = {
cardIconTitle: {
...cardTitle,
marginTop: "15px",
marginBottom: "0px"
}
};
const useStyles = makeStyles(styles);
const GoogleCampaignMonthlyBudgetInput = ({ original, setSubmissionData, submissionData, state, onChange }) => {
return (
<input
id={`monthly_budget${original.id}`}
type="text"
maxLength="12"
size="8"
style={{ float: "left" }}
key={original.id}
onChange={ onChange }
value={submissionData.id === original.id ? submissionData.monthly_budget : original.monthly_budget ? (original.monthly_budget / (1 - (state.customers?.selected?.margin / 100.0))) / 1000000 : ""}
inputprops={{
type: "string",
required: true,
}}
/>
);
}
const MyAccounts = () => {
const [state] = useContext(Context);
const [pageSize, setPageSize] = useState(20);
const customer_id = state.customers?.selected?.id;
const [submissionData, setSubmissionData] = useState({});
let { loading, data } = useQuery(LIST_BUDGETS);
let { loading: googlecampaignloading, data: googlecampaigndata, refetch } = useQuery(GET_GOOGLE_CAMPAIGNS);
googlecampaigndata = googlecampaigndata?.getGoogleCampaigns || [];
data = data?.listBudgets || [];
data = data.map((row, index) => {
let customer_name = "";
let product_line = "";
if (
index % pageSize === 0 ||
row.customer_name !== data[index - 1].customer_name
) {
customer_name = row.customer_name;
}
if (
index % pageSize === 0 ||
row.product_line !== data[index - 1].product_line
) {
product_line = row.product_line;
}
return {
...row,
customer_name,
product_line
};
});
const [submitGoogleCampaignMonthlyBudgetForm, { loading: submitting }] = useMutation(
SUBMIT_GOOGLE_CAMPAIGN_MONTHLY_BUDGET_FORM,
{
variables: {
customerId: customer_id,
data: submissionData
},
onCompleted: () => {
return true;
}
}
);
const classes = useStyles();
return (
<GridContainer>
<GridItem xs={12}>
<Card>
<CardHeader color="trackedKeywords" icon>
<CardIcon>
<Assignment />
</CardIcon>
<h4 className={classes.cardIconTitle}>Google Campaigns</h4>
</CardHeader>
<CardBody>
<ReactTable
key={googlecampaigndata?.length}
data={googlecampaigndata}
loading={googlecampaignloading}
sortable={false}
filterable={false}
columns={[
{
Header: "Monthly Budget",
accessor: "monthly_budget",
Cell: ({ original }) => {
return (
<div>{original.monthly_budget ? (original.monthly_budget / (1 - (state.customers?.selected?.margin / 100.0))) / 1000000 : ""}</div>
);
},
},
{
Header: "Update Monthly Budget",
accessor: "update_monthly_budget",
Cell: ({ original }) => {
return (
<form
onSubmit={e => {
e.preventDefault();
if(submissionData !== {} && submitGoogleCampaignMonthlyBudgetForm()){
refetch();
}
}
}
>
<GoogleCampaignMonthlyBudgetInput original={original} onChange={e => setSubmissionData({...submissionData, "monthly_budget": parseFloat(e.target.value), "id": original.id })} setSubmissionData={setSubmissionData} submissionData={submissionData} state={state} key={original.id} />
<Button
color="primary"
type="submit"
style={{ float: "right" }}
>
Submit
</Button>
</form>
);
},
},
{
Header: "Cycle Start Date",
accessor: "date"
}
]}
defaultPageSize={Math.min(pageSize, googlecampaigndata?.length || 2)}
showPaginationTop
showPaginationBottom={false}
onPageSizeChange={ps => setPageSize(ps)}
className="-striped -highlight"
/>
</CardBody>
</Card>
</GridItem>
</GridContainer>
);
};
export default MyAccounts;
Edit 2: code that I got working with inwerpsel's help!
{
Header: "Monthly Budget",
accessor: "monthly_budget",
Cell: ({ original }) => {
return (
<div>{submissionData.id === original.id ? submissionData.monthly_budget : original.monthly_budget ? (original.monthly_budget / (1 - (state.customers?.selected?.margin / 100.0))) / 1000000 : ""}</div>
);
},
},
{
Header: "Update Monthly Budget",
accessor: "update_monthly_budget",
Cell: ({ original }) => {
const [textInput, setTextInput] = useState(null);
const [submitGoogleCampaignMonthlyBudgetForm, { loading: submitting }] = useMutation(
SUBMIT_GOOGLE_CAMPAIGN_MONTHLY_BUDGET_FORM,
{
variables: {
customerId: customer_id,
data: submissionData
},
onCompleted: () => {
refetch();
return true;
}
}
);
return (
<form
key={"form"+original.id}
onSubmit={e => {
e.preventDefault();
if(Number.isNaN(textInput) || textInput === "" || textInput === null){
setSubmissionData({});
return;
}
submissionData["monthly_budget"] = parseFloat(textInput);
submissionData["id"] = original.id;
if(submissionData !== {} && submitGoogleCampaignMonthlyBudgetForm()){
refetch();
setSubmissionData({});
}
}
}
>
<input
id={`monthly_budget${original.id}`}
type="text"
maxLength="12"
size="8"
style={{ float: "left" }}
key={original.id}
onChange = {event => { setTextInput(event.target.value) }}
defaultValue={submissionData.id === original.id ? submissionData.monthly_budget : original.monthly_budget ? (original.monthly_budget / (1 - (state.customers?.selected?.margin / 100.0))) / 1000000 : ""}
inutprops={{
type: "string",
required: true,
}}
/>
<Button
color="primary"
type="submit"
style={{ float: "right" }}
>
Submit
</Button>
</form>
);
},
},
This GitHub issue seems to indicate that indeed cells will remount as your data changes, even if it's a small change.
In other words, as you type it replaces the whole row with a new instance every character. The new instance has no link to the previous one, even though it should contain the data you typed. As a result it won't have focus.
It seems potentially hard to get around, though I'm not that familiar with react-table.
However, as you already have a form with a submit handler set up, I guess you can just store the input in a local state, and only set it on submit.
Cell: ({ original }) => {
const [textInput, setTextInput] = useState(null);
return (
<form
onSubmit={e => {
e.preventDefault();
// Call the update handler here instead.
const handler = updateFieldHandler("monthly_budget", original.id);
handler(textInput);
if(submissionData !== {} && submitGoogleCampaignMonthlyBudgetForm()){
refetch();
}
}
}
>
<input
// ...
onChange = {event => { setTextInput(event.target.value) }}
// ...
/><Button
color="primary"
type="submit"
style={{ float: "right" }}
>
Submit
</Button>
</form>
);

React - Trying to populate a wizard form by grabbing the ID and allowing the user to make change and conditionally rendered button

Here is what I am trying to accomplish:
I want to allow the user to edit and update information. I am trying to accomplish this by making the form where they can add information to also be the page where they update the information. This information is grabbed by the ID of the listing and would thus populate the rest of the form. However, I'm having trouble trying to figure out the logic to accomplish what it would look like to achieve this goal to its fullest. I believe I am most of the way there but there is something I am missing that I can't quite figure out.
Below is the relevant code:
function AddListing() {
const { state } = useLocation();
const [listingData, setListingData] = useState();
const [isEdit, setIsEdit] = useState(false);
const [formData, setFormData] = useState({
internalName: '',
title: '',
shortDescription: '',
description: '',
locationTypeId: null,
lineOne: '',
lineTwo: '',
city: '',
zip: null,
stateId: null,
latitude: null,
longitude: null,
bedRooms: null,
baths: null,
housingTypeId: null,
accessTypeId: null,
guestCapacity: null,
costPerNight: null,
costPerWeek: null,
checkInTime: null,
checkOutTime: null,
daysAvailable: null,
amenities: [],
name: '',
hasVeteranBenefits: null,
isHostProvided: null,
images: [],
hasVerifiedOwnership: true,
isActive: true,
createdBy: 1,
modifiedBy: null,
});
_logger(formData, 'HookState Test');
_logger(state, 'Edit Listing Data');
const navigate = useNavigate();
const onChange = (values) => {
_logger(values, 'onChange');
setFormData((prevState) => {
const sd = { ...prevState, ...values };
return sd;
});
};
useEffect(() => {
_logger('use effect firing');
setIsEdit((prevState) => {
return {...prevState}
});
if (state?.type === 'LISTING_FORM' && state.payload) {
_logger(state);
setListingData((prevState) => {
return { ...prevState, ...state.payload };
});
}
}, [state]);
const onFinish = () => {
_logger('Finish button clicked', formData);
if (!state) {
listingServices.add(formData).then(onAddListingSuccess).catch(onAddListingError);
} else {
listingServices.update(state.payload.id, listingData).then(onEditListingSuccess).catch(onEditListingError);
}
};
const onAddListingSuccess = (response) => {
_logger(response, 'onAddListingSuccess');
toast.success('Listing Add Success');
navigate('/profile');
};
const onAddListingError = (response) => {
toast.error('Listing Add Error, Please Try Again');
_logger(response, 'onAddListingError');
};
const onEditListingSuccess = (response) => {
_logger(response, 'onEditListingSuccess');
toast.success('Listing Successfully Updated');
navigate('/profile');
};
const onEditListingError = (response) => {
_logger(response, 'onEditListingError');
toast.error('Listing Was Not Updated, Please Try Again');
_logger(response, 'onEditListingError');
};
const wizardSteps = [
{
label: 'Step 1',
icon: <FaHome className="mt-2 text-center" />,
component: <ListingName formData={formData} onChange={onChange} />,
},
{
label: 'Step 2',
icon: <FaLocationArrow className="mt-2 text-center" />,
component: <ListingLocation formData={formData} onChange={onChange} />,
},
{
label: 'Step 3',
icon: <FaHouseUser className="mt-2 text-center" />,
component: <ListingDescription formData={formData} onChange={onChange} />,
},
{
label: 'Step 4',
icon: <HiHome className="mt-2 text-center" />,
component: <ListingAmenities formData={formData} onChange={onChange} />,
},
{
label: 'Step 5',
icon: <ImHome2 className="mt-2 text-center" />,
component: <ListingAvaiServices formData={formData} onChange={onChange} />,
},
{
label: 'Step 6',
icon: <FaImages className="mt-2 text-center" />,
component: <ListingImages formData={formData} onChange={onChange} setFormData={setFormData} />,
},
{
label: 'Step 7',
icon: <BsFileEarmarkTextFill className="mt-2 text-center" />,
component: <ListingPreview formData={formData} onChange={onChange} />,
},
{
label: 'Step 8',
icon: <FaClipboardCheck className="mt-2" />,
component: <ListingFinish formData={formData} onChange={onChange} />,
},
];
return (
<React.Fragment>
<div className="listingWizard">
<Loki steps={wizardSteps} onNext={onChange} onBack={onChange} onFinish={onFinish} noActions />
</div>
</React.Fragment>
);
}
export default AddListing;
In SQL, I have one insert proc that inserts all the data puts in at once. For update, I have each subform being updated via its own proc. I am also having issues with how this should look. Just going to post one subform but I do not know how to accomplish it to where the user can edit only one form of information at a time as opposed to being forced to go and resubmit the rest of the form:
const ListingAmenities = (props) => {
const {
values,
handleBlur,
isSubmitting,
handleSubmit,
setFieldValue,
onBack,
backLabel,
nextLabel,
onNext,
cantBack,
} = props;
_logger(props, 'ListingAmenities props');
useEffect(() => {
onChange();
}, [values]);
const onChange = () => {
props.onChange(values);
};
const onNextClicked = () => {
onNext(values);
};
_logger(values, 'Values');
const options = [
{ label: 'Parking', value: 1 },
{ label: 'Street Parking', value: 2 },
{ label: 'Covered Parking', value: 3 },
{ label: 'Open Parking', value: 4 },
{ label: 'Pool', value: 5 },
{ label: 'Jacuzzi', value: 6 },
{ label: 'Wifi', value: 7 },
{ label: 'Pets Allowed', value: 8 },
{ label: 'Smoking Allowed', value: 9 },
{ label: 'Infant Safe', value: 10 },
{ label: 'Infants', value: 11 },
{ label: 'Patio', value: 12 },
];
const [selected, setSelected] = useState([]);
const handleAmenityChange = (includedList) => {
_logger('handleAmenityChange', includedList);
setSelected(includedList);
if (includedList) {
let amenityId = includedList.map((x) => x.value);
_logger(amenityId, 'Amenities Id');
setFieldValue('amenities', amenityId);
}
};
return (
<React.Fragment>
<Form onSubmit={handleSubmit} className="p-1">
<Card className="p-4 mx-auto" style={{ width: 950 }}>
<Card.Header>
<h3 className="text-center">Listing Amenities</h3>
</Card.Header>
<div className="form-group mt-2">
<label htmlFor="amenities">Available Amenities</label>
<MultiSelect
name="amenities"
options={options}
labelledBy="Select"
value={selected}
onChange={handleAmenityChange}
onBlur={handleBlur}
variant="outlined"
/>
<div className="button-group pt-3 row">
<div className="col-sm-1">
<button
type="button"
className="btn btn-secondary"
onClick={onBack}
disabled={isSubmitting || cantBack}>
{backLabel}
</button>
</div>
<div className="col-sm-1">
<button type="submit" className="btn btn-primary" onClick={onNextClicked}>
{nextLabel}
</button>
</div>
<div className="col-sm-11"></div>
</div>
</div>
</Card>
</Form>
</React.Fragment>
);
};
ListingAmenities.propTypes = wizardPropTypes.listingPropTypes;
export default withFormik({
mapPropsToValues: (props) => ({
amenities: props.formData.amenities,
}),
handleSubmit: (values, { props }) => {
props.onNext(values);
},
})(ListingAmenities);
Lastly, I am unsure of what the logic could look like for the edit button. I was thinking of conditionally rendering based on grabbing the user ID from the params and then applying that to a boolean value so that the user could only edit what it is they need to edit.

How to checked only single checkbox from group of checkboxes in ant design?

I am using Antdesign checkBox to make a section of the filters where users can select different parameters to show data.
const category = [
{ label: "Gardening", value: "Gardening" },
{ label: "Plants", value: "Plants" },
{ label: "Seeds", value: "Seeds" },
{ label: "Bulbs", value: "Bulbs" },
{ label: "Planters", value: "Planters" },
];
export default function SideMenus({ sideOpen, setSideOpen }) {
return (
<div className="row">
{category.map((item) => {
return (
<div className="col-sm-12 px-3 py-2">
<Checkbox key={item.label}>
{item.value}
</Checkbox>
</div>
);
})}
</div>
);
}
In order to check a single checkbox from a group of checkboxes, you have to pass value prop to get value, onChange prop to capture the value, and checked prop to check only that selected single value.
const category = [
{ label: "Gardening", value: "Gardening" },
{ label: "Plants", value: "Plants" },
{ label: "Seeds", value: "Seeds" },
{ label: "Bulbs", value: "Bulbs" },
{ label: "Planters", value: "Planters" },
];
export default function SideMenus({ sideOpen, setSideOpen }) {
const [value, setValue] = useState("");
function handleChange(checkedValues) {
setValue(checkedValues.target.value);
}
return (
<div className="row">
{category.map((item) => {
return (
<div className="col-sm-12 px-3 py-2">
<Checkbox
key={item.label}
onChange={handleChange}
checked={item.value == value}
value={item.value}
>
{item.value}
</Checkbox>
</div>
);
})}
</div>
);
}

Radio buttons for redux form field

It doesn't work correctly, I want to select only one value, but I can select one and more... and can't deselect
there is code for that function.
const RadioButtonField = ({type, options, disabled, onChange}) => {
const handleChange = (value) => {
onChange(type, value);
};
return (
<div>
{options.map(({ value, label }) =>
<Radio.Group key={value}>
<Radio
disabled={disabled}
onChange={() => handleChange(value)}
>
{label}
</Radio>
</Radio.Group>
)}
</div>
);
};
You can try this for single selection and also you can reselect too
import React from "react";
import "./styles.css";
import Radio from "#material-ui/core/Radio";
export default class App extends React.Component {
state = {
selectedValue: null,
radioOptions: [
{ id: 1, title: "1" },
{ id: 2, title: "2" },
{ id: 3, title: "3" },
{ id: 4, title: "4" }
]
};
handleChange = id => {
this.setState({
selectedValue: id
});
};
render() {
const { selectedValue, radioOptions } = this.state;
return (
<div className="App">
{radioOptions.map(option => {
return (
<div className="radio-parent">
<lable
onClick={() => this.handleChange(option.id)}
className="radio-btn"
>
<Radio
color="default"
value={option.id}
name="radioValue"
checked={selectedValue == option.id}
/>
{option.title}
</lable>
</div>
);
})}
</div>
);
}
}
codesandBox link for Demo
You can refer to the following code:
class App extends React.Component {
state = {
initialValue: "A",
options: ["A", "B", "C", "D"]
};
onChange = e => {
console.log("radio checked", e.target.value);
this.setState({
value: e.target.value
});
};
render() {
return (
<Radio.Group value={this.state.initialValue}>
{this.state.options.map((value, index) => {
return (
<Radio onChange={this.onChange} key={index} value={value}>
{" "}
{value}{" "}
</Radio>
);
})}
</Radio.Group>
);
}
}
Working codesandbox demo
I think you do not need to pass anything to the function. Whenever the option will be clicked, the event (e) object will be passed to onChange(e) and you will get the value of clicked item and checked value in onChange(e) e.target.value and e.target.checked respectively.

Resources