Checkbox only changes value when clicked twice - reactjs

As title says, I set up a checkbox which has the issue that I need to click on it twice to change it's state
The first time I click it behaves as expected, but every attempt after that requires double clicking.
state = {
notification: true,
};
handleInputChange= (event) => {
//I use event.target to operate since I'm trying to set up multiple checkboxes
this.setState({ [event.target.id]: !event.target.checked });
};
<AppSwitch
checked={this.state.notification}
onChange={this.handleInputChange}
className={"mx-1 switch-color"}
color={"success"}
variant={"pill"}
id="notification"
name="notification"
/>

You don't need to ! when you're setting state here. It should be this.setState({ [event.target.id]: event.target.checked });, since event.target.checked returns the checked state of the checkbox. So, if you click the checkbox and it transitions to checked, then it will be true. Then, if you click the checkbox and it transitions to unchecked then it will be false.

Related

React state lagging behind reality, causing MUI to display wrong dialog

On a button, I have a onClick handler
const handleSelectOpen = (noteId) => {
let newState = {notes: state.notes, noteDetailScreen: true, activeNote: noteId, newNoteScreen: false, newNoteText: "", newNoteRelated: []};
setState(newState);
};
Which does two important things, it sets noteDetailScreen in the state to true, causing the MUI Dialog to appear. It also sets activeNote to noteId, which is the content that should be displayed in the dialog.
That content is then displayed with {state.notes[state.activeNote].content} inside the dialog. The issue being most of the time, its displaying the wrong content! noteId is always correct, but the state is not always correct. How can I fix this>
when updating state based on the previous state, you should pass an updater function to setState. It takes the pending state and calculates the next state from it.
setState(prev => ({notes: prev.notes, noteDetailScreen: true, activeNote: noteId, newNoteScreen: false, newNoteText: "", newNoteRelated: []}))

React-select onChange trigger when user select same option

The onChange of a react-select drop down is getting triggered when I select an already selected value in the drop down. Is there a way to configure react-select to not trigger onChange event if already selected value is selected again.
handleOnChange(value) {
console.log("test");
this.setState({ multiValue: value });
}
render() {
return (
<div>
<Select.Creatable
options={this.state.options}
onChange={this.handleOnChange.bind(this)}
value={this.state.multiValue}
showNewOptionAtTop={false}
/>
</div>
);
}
As you can see the console log calling even if the value is the same. Codesandbox
You can control the value on onChange of react select.
I changed your onChange function with arrow function:
onChange={value => {
if (value !== this.state.multiValue){
this.handleOnChange(value);
}
}}
codesandbox
I'm not sure whether you can disable the change event but as a workaround You can simply hold the current value of the selected item and return from the change handler if the selected item was the previous one like #ahmetkilinc answer, also menu items have an option
isDisabled
that you can change to true when one item is selected, therefore it can't be selected anymore.

Detect mouse click and change state in React

I have a div which is displayed depending upon a variable- eg: showDiv. After i set showDiv= true, div will appear.
{showDiv && <div id="someid"> text</div>}
Have set a timeout to change variable value so that div will disappear after a time (7 seconds)
thisState.setState({showDiv:true});
setTimeout(function(){
thisState.setState({false});
}.bind(this),7000);
How can i add a code to detect any mouse click and change variable based on that ? Requirement is that, div should disappear either
1. after 7 seconds (already done)
2. based on a click event (if user just clicks on the screen)
Any thoughts ?
You are looking for a window event-listener essentially.
componentDidMount(){
window.addEventListener("click", this.hideDiv)
}
hideDiv = () => {
if(this.state.showDiv){
this.setState({
showDiv: false
})
}
}
Also remember to remove that listener before the component unmounts:
componentWillUnmount{
window.removeEventListener("click", this.hideDiv)
}
See working sandbox: https://codesandbox.io/s/stupefied-silence-snhnw

Force focus to a button element that was disabled in the previous render

I have a button which opens a modal on the onClick event. I want the button to become disabled after the user clicks it, and enabled back when the modal closes.
I have set the initial state of btnDisabled as false and done this: (works as expected)
<Button
label='Mybutton'
className={['btn-outline-primary']}
onClick={this.loadModel}
disabled={this.state.btnDisabled}
/>
The onClick handler of the button is as follows:
loadModel(event) {
this.setState({
ModelOpen: true,
btnDisabled: true,
});
this.activeElement = event.target;
}
The modal close button(x) handler is this:
closeModel() {
this.setState({
ModelOpen: false,
btnDisabled: false,
});
this.activeElement.focus();
}
The problem is that the focus is not shifting to Mybutton. When I try to output document.activeElement.outerHTML on console log, it outputs the close button. Because of this, my tests are failing, as they are expecting MyButton to be the active element.
UPDATE
The tests work fine if I remove the button disabling logic. Here is the assertion that fails:
expect(wrapper.find('.btn-outline-primary').html()).toEqual(document.activeElement.outerHTML);
You are adding eventListener to Button element.
In javascript cause of event bubbling the target may vary.
try using event.currentTarget to get the button instance.
Hope this helps. It will be better if you provide a snippet of issue here.

React Radio Button event on "checked" attribute

I'm trying to handle an event based on the 'checked' attribute of a radio button in React.js. I want the buttons to allow for selecting more than one value, so I removed the 'name' attribute which seemed to disallow multiple selections.
The base radio button component looks like
export function Radio_Button_Multiple_Selection (props) {
return (
<label>
<input type="radio"
checked={props.form_data[props.field_name].indexOf(props.btn_value) > -1}
onClick={props.radio_effect} />
{props.btn_value}
</label>
)
}
I have a form_data objec that has an array of values that correspond to the btn_value of the radio buttons, where if the value is found in the array it should come up as checked. (And this part is working fine right now, they do in fact show up checked as expected):
const form_data = {
...
occupations: ['student', 'merchant', 'paladin', 'troll'],
...
}
Now, I also have a react class with a method for manipulating the values in the occupations array,responding to whether the radio button being licked was already checked or not:
handleRadioButton (event) {
const target = event.target;
const value = target.value;
const isChecked = target.checked;
console.log(isChecked) // this undefined. why?!?
if (isChecked) {
// remove it from array
// etc.
} else {
// add it to array
// etc.
}
}
My main issue is that following:
When I console.log the "checked" logic that returns a boolean inside the RadioButton component's checked attribute, it comes up as expected (true of false if it is or isnt in the array). But it always comes up as checked = undefined in the class method for handling the buttons.
You cannot uncheck a radio button in HTML either. You have to control the checked attribute with your props or state:
Even more, you should rely only on your state, instead of a mix, e.target.checked & state.
class Radio extends Component {
state = {}
render() {
return <input
type="radio"
checked={this.state.checked}
onClick={e => this.setState({
checked: !this.state.checked
})}
/>
}
}
<input type="radio" />
I found the workaround:
use the 'value' attribute to store the same information that I am storing under the 'checked' attribute, with an array that has the button's value AND the checked logic boolean; e.g., value=[boolean, btn_value]
then access the 'value' attribute in the event handler. the value arrives as a full string, so I just split it at the comma and work from there.
it's hacky, but it worked.

Resources