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>
Related
-the select form that allow the user to change the language don't work with onclick how can I use onChange handler
am using react i18next.
*keep in mind that am not getting any errors or warnings.
this is my code
import i18n from 'i18next';
export default function Footer() {
const languages = [
{
code: "fr",
name: "francais",
countryCode:"fr"
},
{
code: "en",
name: "english",
countryCode:"gb"
},
{
code: "ar",
name: "العربية",
countryCode:"sa"
}
]
return <Form.Select aria-label="Default select example" >
{languages.map(({code,name, countryCode})=>{
return(
<option key={countryCode} onClick={()=> i18n.changeLanguage(code)}>{name}</option>
)
})}
</Form.Select>
}
The onChange handler to change the language needs to be set on the Form.Select component, like this: https://codesandbox.io/s/react-code-works-on-mozilla-but-but-dont-on-chrome-forked-1lkvw?file=/src/Footer.js:579-657
import { useTranslation } from "react-i18next";
import { Container, Form } from "react-bootstrap";
export default function Footer() {
const { i18n } = useTranslation();
const languages = [
{
code: "fr",
name: "francais",
countryCode: "fr"
},
{
code: "en",
name: "english",
countryCode: "gb"
},
{
code: "ar",
name: "العربية",
countryCode: "sa"
}
];
return (
<div className="section footer">
<Container>
<Form.Select
defaultValue={i18n.resolvedLanguage}
onChange={e => {
i18n.changeLanguage(e.target.value);
}}
>
{languages.map(({ code, name, countryCode }) => {
return (
<option
key={countryCode}
value={code}
>
{name}
</option>
);
})}
</Form.Select>
</Container>
</div>
);
}
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>
);
}
Hey I'm new to React and I'm having a problem with my prop which I'm passing to my ChildComponent. I am using "react-select" and have two multiselects. Originally I wanted to show in each select the value for the corresponding select I get from the state.
value={optionsColor.filter(item => ( myTest.color.includes(item.value)))}
But this is not possible because one of my calls is always "undefined". For example "myTest.Color" and "myTest.Car" one of them is "undefined" but I don't know why?
In my code (ChildComponent) I have two console.logs which illustrate this.
For example, if I select Color and have previously selected a car in Car, the console.log output looks like this.
undefined
blue
But I want it to output both.
import {useState} from "react";
import ChildComponent from "./ChildComponent";
const ParentComponent = () => {
const [step, setStep] = useState(0)
const [myTest, setMyTest] = useState(
{
color: ['defaultColor'],
car: ['defaultCar'],
}
)
const handleChange = (e, action) => {
setMyTest({ [action.name]: e ? e.map(x => x.value) : [] })
}
return (
<div>
<div className="card-body container mt-3">
<h2>Product data input Intended Use</h2>
<div className="card p-2 mt-5">
<form className="mb-4">
<div className="form"></div>
<ChildComponent myTest={myTest} handleChange={handleChange}/>
</form>
</div>
</div>
</div>
)
}
export default ParentComponent;
import React, { useState } from 'react';
import Select from 'react-select';
const optionsColor = [
{ value: 'blue', label: 'Blue' },
{ value: 'red', label: 'Red' },
{ value: 'yellow', label: 'Yellow' }
]
const optionsCar = [
{ value: 'bmw', label: 'BMW' },
{ value: 'ford', label: 'Ford' },
{ value: 'vw', label: 'VW' },
]
const ChildComponent = ({ handleChange, myTest}) => {
return (
<div>
<h4>Car {console.log(myTest.car)}</h4>
<Select
name="car"
options={optionsCar}
className="mb-3"
onChange={handleChange}
//value={intendedUse.sex === undefined ? '' : optionsSex.filter(item => (intendedUse.sex.includes(item.value)))}
isMulti
autoFocus
isSearchable
/>
<h4>Color {console.log(myTest.color)}</h4>
<Select
name="color"
options={optionsColor}
className="mb-3"
onChange={handleChange}
//value={intendedUse.age === undefined ? '': optionsAge.filter(item => ( intendedUse.age.includes(item.value)))}
isMulti
autoFocus
isSearchable
/>
</div>
)
}
export default ChildComponent;
the problem lies here.
setMyTest({ [action.name]: e ? e.map(x => x.value) : [] })
When you're updating your myTest state you're actually replacing both of the fields with the field you're setting.
Try something like this:
setMyTest(myTest => ({...myTest, { [action.name]: e ? e.map(x => x.value) : [] }}));
In that way, you have a new object with both the field that changed and the one that didn't.
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
I'm trying to build an input form for a project I'm working that submits user data to a database. some of the input fields that are required have over 100 selections that user chooses from. So I wanted to separate those data choices into their own files and them pass props to a select input group to dynamically generate those options. But I'm running into an issue when I try to declare my input component on my form page. I'm getting cannot read property 'map' of undefined. I think its because I'm declaring the input component in the choices file and also the form file. I'll supply the code below so it makes a little more sense.
This is the code that supplies the array data to the input. Its a very long file so ill only post part of it
const BuildingChoices = () => {
const buildingArray = [
{
id: 1,
name: "ACB",
value: "ACB"
},
{
id: 2,
name: "ADH",
value: "ADH"
},
{
id: 3,
name: "AHG",
value: "AHG"
},
{
id: 4,
name: "ANB",
value: "ANB"
},
{
id: 5,
name: "AND",
value: "AND"
},
{
id: 6,
name: "ARC",
value: "ARC"
},
{
id: 175,
name: "WIN",
value: "WIN"
},
{
id: 176,
name: "WMB",
value: "WMB"
},
{
id: 177,
name: "WPR",
value: "WPR"
},
{
id: 178,
name: "WWH",
value: "WWH"
}
]
return (
<SelectInput arrayData={buildingArray} />
)
}
export default BuildingChoices
Here is the select input field that where the options get dynamically generated based on the array passed to it.
import React from 'react'
const SelectInput = (props) => {
return (
<div className="input-group mb-3">
<label className="input-group-text" for="inputGroupSelect01">{props.dataName}</label>
<select onChange={props.onChange} value={props.value} name={props.name} className="form-select" id="inputGroupSelect01">
<option disabled>Choose...</option>
{props.dataArray.map(data => (
<option key={data.id} value={data.value}>{data.name}</option>
))}
</select>
</div>
)
}
export default SelectInput
And then this is the component where the input gets rendered onto the page. It's at the very bottom of the code. I'm pretty sure this is my problem because I'm declaring the in multiple files.
import React, { useState } from 'react'
import SelectInput from "../SelectInput"
const Prjt_Metadata_Form = () => {
const [inputs, setInputs] = useState({
project_id: '',
building: 'Choose...',
measure_type: '',
status: '',
staff_lead: '',
staff_colead: '',
analyst: '',
project_description: '',
nonenergy_benefits: '',
baseline_start_date: '',
reporting_period_start_date: '',
length_baseline_period_days: '',
length_reporting_period_days: ''
});
const { project_id, building, measure_type, status, staff_lead, staff_colead, analyst, project_description,
non_energy_benefits, baseline_start_date, reporting_period_start_date, length_baseline_period_days, length_reporting_period_days } = inputs
const onChange = e => {
const { name, value } = e.target
setInputs({
...inputs,
[name]: value
})
}
const onSubmit = async (e) => {
e.preventDefault();
try {
const body = {
project_id, building, measure_type, status, staff_lead, staff_colead, analyst, project_description,
non_energy_benefits, baseline_start_date, reporting_period_start_date, length_baseline_period_days, length_reporting_period_days
}
const response = await fetch('http://localhost:5000/api/prjt_metadata', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body)
});
window.location = '/'
console.log(response)
} catch (error) {
console.error(error.message);
};
}
return (
<div style={{ minHeight: '45vh' }} className="container d-flex align-items-center mt-5">
<div className="card border-secondary bg-secondary text-center mb-3" >
<div className="card-body text-black">
<form onSubmit={onSubmit}>
<div className="row">
<div className="col-md-4">
<div className="input-group mb-3">
<div className="input-group-prepend">
<span className="input-group-text" id="inputGroup-sizing-lg">Project ID</span>
</div>
<input type="text" name="project_id" className="form-control" value={project_id} onChange={onChange} />
</div>
<SelectInput
onChange={onChange}
value={building}
name="building"
dataName="Building"
/>
Any suggestions on how I can get this working are very appreciated! Thanks!
The problem
Look at how you render your SelectInput:
<SelectInput
onChange={onChange}
value={building}
name="building"
dataName="Building"
/>
Then in SelectInput you map over a prop dataArray which you do not pass as a prop.
props.dataArray.map(data => (
<option key={data.id} value={data.value}>{data.name}</option>
)
Alternative solution
If you don't the SelectInput to be flexible regarding the data used, you can outsource your buildingChoices as a constant to a separate file data.js and include it in your SelectInput to map over it. The relevant parts in your SelectInput.js should then look something like this:
import { buildingChoices } from 'data.js';
buildingChoices.map(data => (
<option key={data.id} value={data.value}>{data.name}</option>
)
However, you could also pass the buildingChoices constant as a prop when rendering `SelectInput
import { buildingChoices } from 'data.js';
<SelectInput
dataArray={buildingChoices}
onChange={onChange}
value={building}
name="building"
dataName="Building"
/>
Your SelectInput component is mapping from props.dataArray but in your Prjt_Metadata_Form component your SelectInput is missing the dataArray
Maybe with a High Order Component approach (HOC)?
const BuildingChoices = (Component) = (props) => {
const buildingArray = [
// { ... }
];
return (
<Component arrayData={buildingArray} {...props} />
)
}
export default BuildingChoices(SelectInput);
Then you can use it like this
<BuildingChoices
onChange={onChange}
value={building}
name="building"
dataName="Building"
/>