Using HTML Selectors with React - reactjs

I'm trying to use the select tag in React. I have the following component:
class InteractionHeader extends React.Component {
constructor(props) {
super(props);
this.state = {
allDays: [],
selected: ""
};
this.dateChanged = this.dateChanged.bind(this);
}
componentDidMount() {
this.setState({
allDays: ["a", "b"],
selected: "a"
});
}
dateChanged(e) {
e.preventDefault();
console.log(event.target.value);
}
}
And in my render, I have the following:
render() {
return (
<div>
<select value={this.state.selected} onChange={this.dateChanged}>
{this.state.allDays.map((x) => {
return <option key={`${x}`} value={`${x}`}>{x}</option>
})};
</select>
</div>
);
}
However, when I select a different option, my console prints undefined instead of the option I selected. What is going on and how do I prevent it?

You are calling it wrong
dateChanged(e) {
console.log(e.target.value);
}
You should use prevent default in case where you donot want your page to take a refresh and try to make a server side call. In case of select there is nothing like this.

You have a typo in dateChanged(e) method. You need to log e.target.value instead of event.target.value.

Related

I wanna console.log the value after clicking the submit button once and to delete the previous mapped items, but it doesnt work

I'm very new to react and I got two problems:
I want to console log the input and display the mapped data after clicking the submit button once. But I get console logged the input and the mapped data after clicking the button twice.
I wanna clear the mapped list (data from previous input) and display new list items depending on the input. But the new list items are only added to the end of the previous list (only the last list item from the previous list got overwritten by the first list item of the new list).
So this is the code from my app component:
import React, { Component, Fragment } from 'react';
import './App.css';
import Display from './/Display';
class App extends Component {
constructor(props) {
super(props);
this.state = {
value: "",
passedValue: ""
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ value: event.target.value });
}
handleSubmit(event) {
this.setState({ passedValue: this.state.value });
console.log(this.state.passedValue);
event.preventDefault();
}
render() {
return (
<div>
<form className="inputContainer" onSubmit={this.handleSubmit}>
<input type="text" name="company_name" onChange={this.handleChange} />
<input type="submit" value="Submit" />
</form>
<Display listDataFromParent={this.state.passedValue} />
</div>
);
}
}
export default App;
And this is my display component:
import React, { Component } from 'react'
import "./Display.css";
export default class Display extends Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
data: []
};
}
componentWillReceiveProps() {
fetch("http://localhost:5000/company?company_name=" + this.props.listDataFromParent)
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
data: result
});
},
// Note: it's important to handle errors here
// instead of a catch() block so that we don't swallow
// exceptions from actual bugs in components.
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
render() {
const { error, isLoaded, data } = this.state;
// if (error) {
// return <div>Error: {error.message}</div>;
// } else if (!isLoaded) {
// return <div>Loading...</div>;
// } else {
return (
<div className="display">
<h1>Kreditnehmer</h1>
<ul>
{this.props.listDataFromParent}
{data.map(item => (
<li key={item.c.company_id}>
Relation type: {item.r.relation_group}
Last name: {item.p.last_name}
</li>
))}
</ul>
</div>
);
}
}
Can anyone help?
1) setState is async method in react means it will take some time to update the component state. You can get your console log by using callback function of setState like
this.setstate({ value: e.target.value }, () => { console.log(this.state.value) });
2) in display component, your using componentWillReciveProps life cycle and inside that your using this.props.listdatafromparent which is pointing previous props. Rather than using this.props I would suggest consider props param of life cycle, means it should be like
componentWillReciveProps(props) {
// your code
Console.log(props.listdatafromparent);
}
The handleSubmit method is wrong... the console log is executed before the state is changed. You need to put it inside a callback function as a second parameter of setState.
this.setState({ passedValue: this.state.value }, () => {
console.log(this.state.passedValue);
});
Answers are:
1) Callback function should be used on setState, in order to do console.log after state is really updated.
In your case you call setState and setState is async function, which means that console.log won't wait until state is really updated.
Your code should be:
handleSubmit(event) {
this.setState({ passedValue: this.state.value },
() => console.log(this.state.passedValue));
event.preventDefault();
}
2) I would move data fetching out of componentWillReceiveProps(), since this lifecycle method will be deprecated from version 17 and it is fired on every render(). Try replacing with componentDidMount() or componentDidUpdate(). Maybe just this small change will solve your problem. If not pls post results and I will take a look again.

DropDown menu is not showing values of the passed array

The values of skillList is not showing in the drop down.it shows an empty dropdown.(the data fetched from api is pushed into the skillList array without any issue)
import React, { Component } from 'react'
let skillList = [];
export class DataCheck extends Component {
constructor(props) {
super(props)
this.state = {
skill: "",
skillId: "",
}
this. handleSkillChange=this. handleSkillChange.bind(this);
}
componentDidMount() {
// worker skill selection
fetch("http://localhost:3001/dataservices/getallskills")
.then (res=>res.json())
.then(res => {
console.log(res);
let temArray = {};
for (let i = 0; i < res.recordsets[0].length; i++) {
temArray["value"] = res.recordsets[0][i].SkillId;
temArray["label"] = res.recordsets[0][i].SkillTitle;
skillList.push(temArray);
console.log(skillList);
temArray = {};
}
})
.catch(function(error) {
console.log(error);
});
}
handleSkillChange(skill) {
this.setState({
skill: skill,
skillId: skill.value
});
}
render() {
return (
<div>
<form>
<select
value={this.state.skill}
onChange={this.handleSkillChange}
options={skillList}
placeholder="Skills"
/>
</form>
</div>
)
}
}
export default DataCheck
when I check the dev-tools, it shows like this:
options:Array
0:Object
label:"wood works"
value:6
(Array consists of 16 objects like this)
console says:
warning.js:36 Warning: Unknown prop options on tag. Remove this prop from the element.
Native select does not have an options props. You have to manually map the option tag:
<select
value={this.state.skill}
onChange={this.handleSkillChange}
placeholder="Skills"
>
{this.state.skillList.map((optionSkill) => (
<option value={optionSkill.value}>{optionSkill.label}</option>
)}
</select>
Currently you have added skillList as a normal variable with module scope. Even though you have changed skillList, the same will not be reflected in the UI because React does not detect this change. you will have to change skillList to a state variable for React.
this.state = {
skill: "",
skillId: "",
skillList: []
}
fetch("http://localhost:3001/dataservices/getallskills")
.then (res=>res.json())
.then(res => {
this.setState({
skillList: res.recordsets[0].map((recordSet) => ({
label: recordSet.SkillTitle,
value: recordSet.SkillId,
}))
});
});
You have to add option tag inside select. Loop array of items using .map and you will get your result.
This codepen can help you to make this work,
select example
Hope this can help you!

RadioButton click TypeError: Cannot read property 'setState' of undefined

I'm trying to set the state based on the radio button clicked.
My Code:
import React, { Component } from 'react';
class MyApp extends Component {
state={
name: "SomeName",
radio: "some"
}
onRadioChange(e) {
this.setState({name:"New Name"});
// this.setState({
// [e.target.name]: e.target.value;
// })
}
render() {
return (
<div style={{marginBottom:"50px"}}>
<input type="radio" onChange = {this.onRadioChange}
value="JonSnow"
name="radio1" />
<label>JonSnow</label>
<input type="radio" onChange = {this.onRadioChange}
value="Cleopatra"
name="radio1"/>
<label>Cleopatra</label>
</div>
);
}
}
export default MyApp;
Whenever I click on the radio button, I get an error:
TypeError: Cannot read property 'setState' of undefined
What am I doing wrong?
In order to use this keyword, you need to bind the method. Or as a workaround you can use the arrow function.
Like this:
onRadioChange = (e) => {
this.setState({name:"New Name"});
// this.setState({
// [e.target.name]: e.target.value;
// })
}
You have two options here. Either use arrow function or bind your function to this inside your constructor.
Why is it not working?
This is because in order to use setState anywhere you must have access to this.
Arrow functions do not need to be explicitly bound to this and since is a shorter choice for achieving what you want. (They are bound to this beforehand).
First option:
onRadioChange = (e) => {
this.setState({ name: 'newName' });
}
Second option:
class MyApp extends React.Component {
constructor(props) {
super(props);
this.onRadioChange = this.onRadioChange.bind(this);
};
}

Is it possible to open React-Select component as it mounts?

Not just focusing, but to actually open the component and display options.
I know this isn't simple on a regular select component (see Is it possible to use JS to open an HTML select to show its option list? ), but perhaps it is still possible with React-Select.
In react-select you can control the opening of the menu with menuIsOpen props. to achieve your goal I would use a combination of menuIsOpen, onInputChange and onFocus like this:
class App extends Component {
constructor(props) {
super(props);
this.state = {
menuIsOpen: true
};
}
onInputChange = (options, { action }) => {
if (action === "menu-close") {
this.setState({ menuIsOpen: false });
}
};
onFocus = e => {
this.setState({ menuIsOpen: true });
};
render() {
return (
<div className="App">
<Select
options={options}
onFocus={this.onFocus}
onInputChange={this.onInputChange}
menuIsOpen={this.state.menuIsOpen}
/>
</div>
);
}
}
onInputChange can receive the following events:
"set-value",
"input-change",
"input-blur",
"menu-close"
Depending of what kind of behaviour you're expecting I would update this live example.

Reactjs Select v2 - How to handle Ajax Typing?

I am using reactjs select 2 but I don't know how to make it work so that when a user types something in a ajax request is made and the results are sent back.
I see it has some async options but I don't get how it works and how I would get it to work with axios.
I come up with this but it is kinda laggy when a user types(probably because it is re-rendering it after each type) and when the user selects a choice the value disappears.
export default class TestComponent extends Component {
constructor(props) {
super(props);
this.state = {value: ""};
}
onInputChange(option) {
this.getOptionsAsync(option)
}
getOptionsAsync(newInput) {
var that = this;
console.log("ffd", newInput)
axios.get(`https://localhost:44343/api/States/GetStatesByText?text=${newInput}`)
.then(function (response) {
var formatedResults = response.data.map((x)=> {
return {value: x.id, label: x.name}
})
that.setState({
options: formatedResults,
value: newInput
})
})
.catch(function (error) {
});
}
render() {
console.log(this.state.value, "value")
return (
<div className="test">
<Select
onInputChange={this.onInputChange.bind(this)}
value={this.state.value}
options={this.state.options }
/>
</div>
);
}
}
You're going to be doing an api call every single time that you type a letter with the current way you're doing things. I would recommend just loading the states once at the beginning, perhaps in your ComponentDidMount() method.
If you pass the isSearchable prop to React-Select it will automatically work as a filter anyways.
Another thing I've had to do in this case which I believe will fix your change problem is to make sure it calls the handler on change not just on input change.
Pass this prop:
<Select
value={this.state.value}
options={this.state.options }
onChange={value => {
if (value) this.onInputChange(value)
else this.onInputChange('')
}
/>
Due to the way this is automatically bound to arrow functions, you won't have to bind to this if you change your onInputChange to the following:
onInputChange = (value) => {
this.getOptionsAsync(value)
}
Finally, you should be setting the state in the above function so the value is stored.
onInputChange = (value) => {
this.getOptionsAsync(value)
this.setState({value})
}

Resources