This is my react functional component, I am sending inputs as props which are to be displayed and then looping through the inputs to check which inputs are to be displayed according to condition. This is my component :-
const TopInputComponent = (props) => {
const inputs = props.inputs;
inputs.map((input,index)=>{
if(input.type == "textInput"){
return (<Textfield key={index}
onKeyDown={(event)=>{
if(event.key == "Enter"){
onFilterSelected({'min_price':parseInt(event.target.value)});
}
}}
label={input.placeholder}
floatingLabel
/> )
}else if(input.type == "selectInput"){
return (<div key={index}>
<label>{input.placeholder}</label>
<select >
<option value="1">1</option>
<option value="2">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
</div>)
}
})
}
I am getting this Error :
"A valid React element (or null) must be returned. You may have
returned undefined, an array or some other invalid object."
There are two, three, possibly four problems:
You aren't returning anything out of the function, because you haven't returned the result of map.
A React component must return a single element or null, it can't return an array.
Within your map callback, you're only returning something if input.type is "textInput" or "selectInput", not if it's something else. That will leave undefined values in your resulting array. If those are the only two possible values, change else if(input.type == "selectInput"){ to just } else {. If not, handle the other cases.
floatingLabel in the Textfield's start tag seems odd, it will be a freestanding boolean attribute.
So you'll probably want to wrap those elements in something, perhaps a div (see *** lines):
const TopInputComponent = (props) => {
const inputs = props.inputs;
return <div>{inputs.map((input,index)=>{ // ***
if(input.type == "textInput"){
return (<Textfield key={index}
onKeyDown={(event)=>{
if(event.key == "Enter"){
onFilterSelected({'min_price':parseInt(event.target.value)});
}
}}
label={input.placeholder}
floatingLabel
/> )
} else { // *** Removed: if(input.type == "selectInput"){
return (<div key={index}>
<label>{input.placeholder}</label>
<select >
<option value="1">1</option>
<option value="2">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
</div>)
}
})}</div>; // ***
}
Simplified live example:
const MyComponent = props => {
const {inputs} = props;
return <div>
{inputs.map((input, index) => <input key={index} type={input.type} name={input.name} value={input.value || ''} />)}
</div>;
};
ReactDOM.render(
<MyComponent inputs={[
{type: "text", name: "one"},
{type: "button", name: "btn", value: "Click me"}
]} />,
document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Inside map you are returning the elements, that elements will group into an array by map (returns an array), You need to return the result of map also. You are returning an array but react component can't return an array, so wrap the map result inside a div.
Use this:
const TopInputComponent = (props) => {
const inputs = props.inputs;
return <div> { inputs.map((input,index)=>{ //added return
....
One more issue is, inside map if you don't return anything by default it will return undefined, you are using two condition, may be possible if none of them is true, in that case undefined will be returned. So always use a default case also, use it in this way:
return a.map(el => {
if(/*condition 1*/)
return //1;
else if(/*condition 2*/)
return //2;
else
return //3;
})
Check this example:
a = [1,2,3,4,5,6];
function withoutReturn () { a.map(i => i); };
function withReturn () { return a.map(i => i); };
console.log('withoutReturn', withoutReturn());
console.log('withReturn', withReturn())
Related
I tried many ways to select some options from the select, but it didn't work. Could you help to solve my problem, please? When I do a console.log, the selected options change, but the frontend doesn't show it. It keeps the default option "Select the option." I am using react-bootstrap and firebase. I don't know what the error is. I was thinking about the browser, but it is not the problem.
class Formm extends Component {
constructor(props) {
super(props);
this.state = {
detail: "",
cost: 0,
category: ""
};
this.setCategory = this.setCategory.bind(this);
console.log(this.state);
}
setCategory = (e) => {
let index = e.target.selectedIndex;
this.setState({ category: e.target.value});
console.log(e.target.value)
};
render() {
const { detail, cost, category } = this.state;
return (
<div>
<FirebaseDatabaseProvider firebase={firebase} {...firebaseConfig}>
<FirebaseDatabaseNode path="category/">
{(data) => {
const { value } = data;
if (value === null || typeof value === "undefined") return null;
const values = Object.values(value);
return <div className="row justify-content-center">
<div className="form-group col-md-6">
<label htmlFor="">Insert the type:</label>
<select
onChange={this.setCategory}
value={category}
className="form-control"
>
<option value={null}>Select the option</option>
{values.map((value) => {
return (
<option key={value} value={value}>
{value}
</option>
);
})}
</select>
</div>
</div>;
}}
</FirebaseDatabaseNode>
</FirebaseDatabaseProvider>
</div>
It’s because you’re using “this” keyword inside of an arrow function that your set state doesn’t run.
“this” refers to the Class itself, but an arrow function, unlike a standard function, has no reference to the Class even though it’s defined within the Class.
Fortunately there’s an easy fix:
If you change setCategory to a function using the function keyword your code will run as you expect.
Essentially I have a select dropdown that is being populated by an API.
If you look at the following code snippet, I essentially created an array of IDs called "first" and made it the value for the first select option above the map that I've done to populate the rest of the select.
Now in my handleChange when I log the value of a selected option it returns the value of the given option in an array of string numbers.
--> Example... if user selects the second option ['1']
When the user selects 'All IDs' that's where the issue is. When that option is selected whats logged is ---> ['1,2,6,8,15,16,17,20,22,23,24,25,26,27,30,32,33,34,36']
I understand that I could use the split method but it crashes for any other option that's selected.
How could I get around that?
const DropDown = ({ list = [], title, onChange }) => {
const handleChange = (e) => {
const { value } = e.target
const arr = [value]
console.log(arr)
// onChange(Number(value))
}
const first = list.map((list) => list.id)
return (
<>
<select onChange={handleChange}>
<option value={first}>{title}</option>
{list.map((item) => (
<option key={item.id} value={item.id}>
{item.name}
</option>
))}
</select>
</>
)
}
e.target.value is a string, so you'll need to change this:
const arr = [value]
to
const arr = value.split(",").map(Number);
You can use whatever you want as the value (key) of the "All" option. For example, in the following, I've used "all" as the key and handled that specifically in the handleChange handler.
const DropDown = ({ list = [], title, onChange }) => {
const handleChange = (e) => {
const { value } = e.target;
if (value === "all") {
onChange(list.map((l) => l.id));
} else {
onChange([parseInt(value, 10)]);
}
};
return (
<>
<select onChange={handleChange}>
<option value="all">{title}</option>
{list.map((item) => (
<option key={item.id} value={item.id}>
{item.name}
</option>
))}
</select>
</>
);
};
You can use value.split(",") as well, which would work for your specific example but would not be sufficient if you need to handle different types of items in the list (perhaps strings that could contain their own ,s).
Here's the above code in action
I'd like to know how to get the object properties from a json.
I got this fake API:
{
"Arreglo":[
{ "label": "Choose Wisely", "value": "Choose Wisely"},
{ "label": "Primer opción", "value": "1", "testvariable": [] },
{ "label": "Segunda opción"," value": "2" },
{ "label": "Tercer opción", "value": "3" }
]
}
This is my App.js :
import SelectComponent from './Components/SelectComponent';
import {Arreglo} from './FakeApis/SelectOptions';
function App() {
return (
<div className="App">
<SelectComponent items1 = {Arreglo}/>
</div>
);
}
And this is my form and how I set the state:
export default function SelectComponent(items1) {
console.log(items1.items1);
const[testVar, testFunction] = useState(false);
const [items] = React.useState(items1.items1);
<form>
<select onChange = {handleChange}>
{items.map(item => (
<option
key={item.value}
value={item.value}
label={item.label}
>
{item.label}
</option>
))}
</select>
</form>
In this function I'd like to know how to get the "testvariable"
const handleChange = event => {
console.log("The variable --->");
};
Hope I explained myself good.
regards!
Since your data doesn't have any unique identifying id, you can use the index of each item in the array as a reference point that you can use in your change handler.
To do this, first read your data into some piece of state. While your data is static now, this is good practice for when you start speaking to an actual API to fetch data.
Once you have that data available within your component (you can abstract this back into a separate Select Component, I just did it one file for ease of understanding), you can access the selected option by using the selectedIndex property of the event within the change event handler.
import {Arreglo} from './FakeApis/SelectOptions';
export default function App() {
// Read the data into state
const [data] = React.useState(Arreglo);
const handleChange = e => {
// The index of the selected option
const { selectedIndex } = e.currentTarget;
// Grab the element at that index
const selectedOption = data[selectedIndex];
// You can now access any property on that element, like testVariable
console.log(selectedOption.testvariable);
};
return (
<div className="App">
<select onChange={handleChange}>
{data.map(item => (
<option key={item.value} value={item.value} label={item.label}>
{item.label}
</option>
))}
</select>
</div>
);
}
To access the testVar your handleChange function must be inside the SelectComponent function just like the testVar:
export default function SelectComponent(items1) {
const[testVar, testFunction] = useState(false);
const [items] = React.useState(items1.items1);
const handleChange = event => {
// testVar can be called here
}
<form>
<select onChange = {handleChange}>
{items.map(item => (
<option
key={item.value}
value={item.value}
label={item.label}
>
{item.label}
</option>
))}
</select>
</form>
Something that you could do in order to solve your issue and have access to your data is to replace your select tag by the following:
<select onChange = {(event) => handleChange(event, items)}>
{items.map(item => (
<option
key={item.value}
value={item.value}
label={item.label}
>
{item.label}
</option>
))}
</select>
And let your handleChange function accept another parameter:
const handleChange = (event, items) => {
// items is now available in this block and you can get testvariable here.
console.log(`The variable ${items}`);
};
I am looping through an array in react using map function to return option tags for HTML select tag. But it does not seem to work. Project_titles array is properly populated with data.
I have used same code in some other place and it is working there.
render() {
<select
id="sel4"
onChange={event => this.setState({ project: event.target.value })}
>
{this.func()}
</select>;
}
func() {
this.state.project_titles.map(function(title, i) {
return (
<option key={i} value={title}>
{title}
</option>
);
});
}
Select tag should get populated with options but it is empty.
This works. The issue with your code is you are not returning the final Options array from you func() function.
render(){
<select
id="sel4"
onChange={event => this.setState({ project: event.target.value })}
>
{this.func()}
</select>;
};
func = () => {
return this.state.project_titles.map(function(title, i) {
return (
<option key={i} value={title}>
{title}
</option>
);
});
};
Its suppose return component that realize dropdown list by getting array of strings. Its probably some mistake how use elements of array.
import React from 'react'
class DropDownList extends React.Component {
renderDropDownList = () => {
const { dropDownDownData } = this.props
return (
<div className="book-shelf-changer">
<select>
dropDownDownData.map(function(item){
<option key = {item} value={item}>{item}</option>
})
</select>
</div>
)
}
render() {
const optionList = ['Move to...','Currently Reading','Want to Read','Read','None']
return this.renderDropDownList(optionList)
}
}
export { DropDownList }
I think it's just because you have forgotten some curly braces to call dropDownData function and your function is not interpreted as Javascript function. Add a return to your map function too.
It should work with this :
<select>
{dropDownDownData.map(function(item){
return (<option key = {item} value={item}>{item}</option>);
})}
</select>
You can also use ES6 syntax for your map expression :
<select>
{dropDownDownData.map(item => (<option key = {item} value={item}>{item}</option>))}
</select>