reactjs change state of select with out clicking on it - reactjs

I have the following select component in my react program:
<select>
<option>option1</option>
<option>option2</option>
</select>
I'd like to be able to change which option is selected when some event takes place, say pressing a button, in addition to being able to change which option is selected by interacting with the drop down menu. How can I do this? Here is an example of what I mean:
<select>
<option>option1</option>
<option>option2</option>
</select>
<button/> // when this button is pressed I want
// the selected option to change to option1
// regardless of the selects current state
Thanks
Please note: I am not asking how to change the default state of the select, I want to be able to change it at run time by pressing a button

Set a state variable to control the selected value and then update that state variable onClick of a button.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedOption: ""
};
}
handleChange = event => {
this.setState({selectedOption: event.target.value});
}
handleClick = () => {
this.setState({selectedOption: "foo"});
}
render() {
return (
<div className="App">
<select value={this.state.selectedOption} onChange={this.handleChange}>
<option value="">Default</option>
<option value="foo">Foo</option>
<option value="bar">Bar</option>
</select>
<button onClick={this.handleClick}>Click Me</button>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('app'))
<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>
<div id='app' />

Related

ReactJs: Rendering Similar React Components from a list without using same states for each of the element

I have a CustomReactComponent class which holds a list of similar React Components, I then render a single element Component from the list based on some condition.
This Component has <input/> tag.
When I try to render it all the <input/> tags have the same value when User changes only one of them.
How can I prevent this from happening? and have the inputs store differnt values for each instance
Minimal Reproducible Code:
import {Component} from "react";
export default class CustomReactComponent extends Component {
constructor(props) {
super(props);
this.state = {selected: 0};
this.list = [<div><input/></div>, <div><input/></div>, <div><input/></div>, <div><input/></div>];
}
onSelect = (e) => {
this.setState({selected: e.target.value});
}
render() {
let Component = this.list[this.state.selected];
return (
<div>
<select onChange={this.onSelect}>
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<div>
State:{this.state.selected}:
{Component}
</div>
</div>
);
}
}
Edit 1:
As #asynts pointed out we could use key for each component, but keys's check for siblings during rendering, and since here i am rendering only a single component, key would be of no use, it re-initializes the component every time the state selected changes. But this is a start, it atleast dosent treat all the components in this.list as the same thing
Edit 2:
After some tinkering and experimentation I found a work around for this, we can have a Wrap Component which is given a unique id uid as a prop this can then be used during rendering if state selected points to uid of a Wrap we style it to display: initial else to display: none, this is where key's comes handy we can always render all the siblings and give it a key same as uid
Code:
import {Component} from "react";
function Wrap({uid}) {
return <div>uid = {uid} : <input/></div>
}
export default class CustomReactComponent extends Component {
constructor(props) {
super(props);
this.state = {selected: 0};
this.list = [
<Wrap uid={0}/>,
<Wrap uid={1}/>,
<Wrap uid={2}/>,
<Wrap uid={3}/>
];
}
onSelect = (e) => {
this.setState({selected: parseInt(e.target.value)});
}
render() {
return (
<div>
State:
<select onChange={this.onSelect}>
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<div>
{this.list.map((component) =>
<div key={component.props.uid}
style={{display: component.props.uid !== this.state.selected ? 'none' : 'initial'}}>
{component}
</div>)}
</div>
</div>
);
}
}
This is actually a much more interesting problem than I originally thought.
It seems that React simply can't tell that you are rendering a different element.
Ultimately, the JSX syntax is just syntactic sugar for React.createElement which returns an object:
// jsx:
<input />
// js:
React.createElement("input");
// result object:
{
type: "input",
// This is the default.
key: null,
// There is some other stuff in here too.
}
In other words, all the entries in your array are identical as far as React is concerned.
You can resolve this problem by specifying a key attribute in each array entry:
this.list = [
<div key="1"><input/></div>,
<div key="2"><input/></div>,
<div key="3"><input/></div>,
<div key="4"><input/></div>,
];
There is some documentation about this but it's a bit vague.
Here is an in-depth explanation about why keys are necessary if you’re interested in learning more.
TL;DR: React will create a tree of these objects I mentioned and then computes the difference to the previous tree and updates the DOM. In your case, it is not able to find a difference and therefore needs the key attribute to help.
We could use key for each component, but key's check for siblings during rendering, and here only a single component is being rendered, thus making key not so useful, it re-initializes the component every time the state selected changes.
But we can have a Wrap Component as a work around, Wrap is given a unique id uid as a prop this can then be used during rendering if state selected points to uid of a Wrap we style it to display: initial else to display: none, this is where key's comes handy we can always render all the siblings and give it a key same as uid
Code:
import {Component} from "react";
function Wrap({uid}) {
return <div>uid = {uid} : <input/></div>
}
export default class CustomReactComponent extends Component {
constructor(props) {
super(props);
this.state = {selected: 0};
this.list = [
<Wrap uid={0}/>,
<Wrap uid={1}/>,
<Wrap uid={2}/>,
<Wrap uid={3}/>
];
}
onSelect = (e) => {
this.setState({selected: parseInt(e.target.value)});
}
render() {
return (
<div>
State:
<select onChange={this.onSelect}>
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<div>
{this.list.map((component) =>
<div key={component.props.uid}
style={{display: component.props.uid !== this.state.selected ? 'none' : 'initial'}}>
{component}
</div>)}
</div>
</div>
);
}
}

Auto focus first time on loading page

There is a input text in center in which I want to focus when the page loads, so I have used componentDidMount() and set the focus.
componentDidMount() {
this.inputBar.focus();
}
.
.
<input type="text" ref={(element) => { this.inputBar = element; }}>
but it isn't working as a sidebar pops in as the page loads and shifts the focus from the center input.
I tried to use componentDidUpdate() but then it triggers the focus again and again when I close the sideBar. I only want to focus only at first time when I load the page.
I am new at coding, please suggest something that can be done here.
Thanks in advance.
you have to create ref , then in your lifecycle method use that ref, you have forgotten to use current when you are using ref in lifecycle method, your code will be like this:
class GroupDetail extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
componentDidMount(){
this.ref.current.focus()
}
render(){
return(
<input type="text" ref={this.inputRef}/>
)
}
}
If you want to focus a single Input then you can simply do
<input type="text" autofocus>
If you just want to focus an element when it mounts (initially renders) a simple use of the autoFocus attribute will do.
<input type="text" autoFocus />
Or if you want to do it with componentDidMount and to control focus dynamically you can go with the below snippet
class App extends React.Component{
componentDidMount(){
this.nameInput.focus();
}
render() {
return(
<div>
<input defaultValue="Won't focus"/>
<input ref={(element) => { this.nameInput = element; }} defaultValue="will focus"/>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>

What are the differences between defaultValue and value in select?

I have two react components, parent and child. I'm passing a prop to a child component, and I want to use that prop to set the defaultValue on a select input. However, if that property changes, I'd like for the select default value to change as well.
When I set default value in select, I can choose one of the options that is a part of that selector. If I use value instead, the 'default' changes as the property updates, but I can't select any of the options.
class Selector extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<select defaultValue={this.props.value}>
<option>1</option>
<option>2</option>
</select>
)
}
}
I'd like for the value to change, and I realize that it is not re rendering even though the prop has changed. I'm looking for a work around.
I'm quoting:
The difference between the defaultValue and value property, is that
defaultValue contains the default value, while value contains the
current value after some changes have been made. If there are no
changes, defaultValue and value is the same.
The defaultValue property is useful when you want to find out whether
the contents of a text field have been changed.
What that actually means is that if you put defaultValue, this value will be initialized to the input and that's it, you can change value and the text will change.
But if you put value, you would need to change that value given to the input in the first place in order for input text to change.
Look at this example, all using the same state, but behaving differently.
// Example class component
class Thingy extends React.Component {
constructor(props) {
super(props);
this.state = { value: 'test' }
}
onChange(e) {
this.setState({ value: e.target.value });
}
render() {
return (
<div>
<div><b>default value</b> (you can edit without changing this.state.value)</div>
<input defaultValue={this.state.value}></input>
<div><b>value</b> (you can't edit because it does not change this.state.value)</div>
<input value={this.state.value}></input>
<div><b>value</b> (you can edit because it has onChange method attached that changes this.state.value) <br /> <b>NOTE:</b> this will also change second input since it has attached the same state with <b>value</b> property, but won't change first input becase same state was attached as <b>defaultValue</b></div>
<input value={this.state.value} onChange={e => this.onChange(e)}></input>
</div>
);
}
}
// Render it
ReactDOM.render(
<Thingy />,
document.body
);
div > div {
font-size: 16px;
}
input + div {
margin-top: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<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>
When you don't have onChange handler you need to put your value as defaultValue, but in value when you have onChange handler.
You can do this,
class Selector extends React.Component {
constructor(props) {
super(props);
this.state = {
selected: props.value
}
}
change = (event) =>{
this.setState({selected: event.target.value});
}
componentDidUpdate(prevProps, prevState) {
if (prevState.selected !== this.props.value) {
this.setState({selected: this.props.value})
}
}
render() {
return (
<select value={this.state.selected} onChange={this.change}>
<option>1</option>
<option>2</option>
</select>
)
}
}
defaultValue is selected value while very first time loading
and
value is selected value every time to change option value

React form input won't let me change value

I have a component in a React class in my Laravel project which is a simple form with one input field. It houses a phone number which I have retrieved from the database and passed back through the reducer and into the component as a prop. Using this, I have passed it through to the module as a prop which then populates the field with the currently saved value:
<OutOfOfficeContactNumberForm
show={props.showOutOfOffice}
value={props.outOfOfficeNumber}
handleChange={console.log("changed")}
/>
I have a handleChange on here which is supposed to fire a console log, but it only ever displays on page load. Here is my form module class:
class OutOfOfficeContactNumberForm extends React.Component {
render() {
const { show, value, handleChange } = this.props;
if(!show) return null;
return (
<div>
<p>
Please supply an Out of Office contact number to continue.
</p>
<InputGroup layout="inline">
<Label layout="inline" required={true}>Out of Office Contact Number</Label>
<Input onChange={handleChange} value={value} layout="inline" id="out-of-office-number" name="out_of_office_contact_number" />
</InputGroup>
</div>
);
}
}
export default (CSSModules(OutOfOfficeContactNumberForm, style));
The form is embedded in my parent component, as follows:
return (
<SectionCategoriesSettingsForm
isSubmitting={this.state.isSubmitting}
page={this.props.page}
show={this.props.show}
categories={this.props.categories}
submitSectionCategoriesSettings={this._submit.bind(this, 'add')}
updateSelectedCategories={this._updateSelectedCategories.bind(this)}
selectedCategoryIds={this.state.selectedCategoryIds}
storedUserCategories={this.props.selectedCategories}
outOfOfficeNumber={this.state.outOfOfficeNumber}
onUpdateContactNumber={this._updateContactNumber.bind(this)}
/>
);
In my componentWillReceiveProps() function, I set the state as follows:
if (nextProps.selectedCategories && nextProps.selectedCategories.length > 0) {
this.setState({
outOfOfficeNumber: nextProps.outOfOfficeNumber,
selectedCategoryIds: nextProps.selectedCategories.map(c => c.id)
});
}
I'm pretty sure the reason it's not changing is because it's pre-loaded from the state which doesn't change - but if I cannot edit the field how can I get it to register a change?
EDIT: Just to clarify there are also checkboxes in this form for the user to change their preferences, and the data retrieved for them is set the same way but I am able to check and uncheck those no problem
Changes:
1- onChange expect a function and you are assigning a value that's why, put the console statement inside a function and pass that function toOutOfOfficeContactNumberForm component , like this:
handleChange={() => console.log("changed")}
2- You are using controlled component (using the value property), so you need to update the value inside onChange function otherwise it will not allow you to change means input values will not be not reflect in ui.
Check example:
class App extends React.Component {
state = {
input1: '',
input2: '',
}
onChange = (e) => this.setState({ input2: e.target.value })
render() {
return(
<div>
Without updating value inside onChange
<input value={this.state.input1} onChange={console.log('value')} />
<br />
Updating value in onChange
<input value={this.state.input2} onChange={this.onChange} />
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('app'))
<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>
<div id='app' />
I think the best way is when you get data from database put it to state and pass the state to input and remember if you want to see input changes in typing, use a function to handle the change and that function should change state value.
class payloadcontainer extends Component {
constructor(props) {
super(props)
this.state = {
number:1
}
}
render() {
return (
<div>
<input value={this.state.number} onChange={(e)=>this.setState({number:e.target.value})}></input>
<button onClick={()=>this.props.buyCake(this.state.number)}><h3>buy {this.state.number} cake </h3></button>
</div>
)
}
}

How to set placeholder for dropdown in react js?

<select>
<option selected disabled>Select</option
I added an extra option with a disabled property, but this gives me the following warning:
Use the defaultValue or value props on select instead of setting
selected on option.
<select>
{this.props.optionarray.map(function(e){
return <option
value={e[self.props.unique]}
key={e[self.props.unique]}
>
{e[self.props.name]}
</option>
})}
</select>
optionarray is an array which is passed through props to be mapped on each index which has an object and I pass the key through props as well which was in the array. Everything is working here, it's just showing me the warning that I mentioned above.
How do I remove that or how do I set a perfect placeholder for a dropdown in react?
Reason is, React provide a better way of controlling the element by using states, so instead of using selected with option use the value property of select and define its value in the state variable, use the onChange method to update the state, Use it in this way:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: '1'
};
}
render(){
return(
<select value={this.state.value} onChange={(e)=>{this.setState({value: e.target.value})}}>
<option value='1' disabled>Select</option>
{
[2,3,4].map((i,j)=>{
return <option key={i} value={i}>{i}</option>
})
}
</select>
);
}
}
How to set placeholder for dropdown?
According to Mozilla Dev Network, placeholder is not a valid attribute on a <select>. So in place of that you can you this also to render a default option:
<option default>Select</option>
Use of key as per DOC:
Keys help React identify which items have changed, are added, or are
removed. Keys should be given to the elements inside the array to give
the elements a stable identity.
Suggestion:
Whenever we create any ui dynamically in loop, we need to assign a unique key to each element, so that react can easily identify the element, it basically used to improve the performance.
Check the working example:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: '1'
};
}
render(){
return(
<select value={this.state.value} onChange={(e)=>{this.setState({value: e.target.value})}}>
<option value='1' disabled>Select</option>
{
[2,3,4].map((i,j)=>{
return <option key={i} value={i}>{i}</option>
})
}
</select>
);
}
}
ReactDOM.render(<App />, document.getElementById('container'));
<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>
<div id='container'/>
Check the fiddle for working example: https://jsfiddle.net/29uk8fn0/
Functional Component
import { useState } from "react";
export default function DropdownComponent(props) {
const [formData, setFromData] = useState({
anyInput: "something",
dropdownInput: null,
});
return (
<>
anyInput: { formData.anyInput }
dropdownInput: { formData.dropdownInput }
<select name={"dropdownName"} onChange={ ({target})=> {
setFromData((prev)=> ({...prev, dropdownInput:target?.value}) );
}
}>
<option key='blankKey' hidden value >Placeholder Text for Select</option>
{
[2,3,4].map((i,j)=>{
return <option key={i} value={i}>{i}</option>
})
}
</select>
</>
)
}

Resources