I'm using a Material UI Table with ReactJS and would like to change a state variable whenever a row is selected/deselected. Table has onRowSelection which is triggered each time a row is selected:
<Table
height='300px'
fixedHeader={true}
multiSelectable={true}
showRowHover={true}
onRowSelection={this.handleRowSelection.bind(this)}
>
I have the following function passed to the onRowSelection prop:
handleRowSelection(selectedRows) {
let contactsImport = [];
if (selectedRows === 'all') {
contactsImport = this.state.contacts.new;
} else if (selectedRows !== 'none') {
selectedRows.forEach((index) => {
contactsImport.push(this.state.contacts.new[index]);
});
}
this.setState({
contactsImport:contactsImport
});
}
This sets the state correctly, however it prevents the Table Row selection from functioning correctly. If I click a row, the checkbox doesn't check -- it seems like it is checking and then instantly unchecking itself because I get the 'ripple' animation but no checkmark.
Removing the call to setState fixes the issue, so is it possible setState is preventing the callback from returning correctly? Or might this be a bug with Material UI?
You'll have to manage the selected property of a single row component from the state if you wish to control it programmatically. selected property is false by default, so when rerendering happens by setState it'll be reset back to false
Related
I'm using DownshiftJS to create an Autocomplete component using the useCombobox hook. It's all going well and testing with react-hook-form. Unfortunately, I've hit a problem where the reset function available within react-hook-form, which fires the HTMLFormElement.reset() method, does not trigger any state/input change within the Downshift component.
This means that when a user selects an item from the list (which triggers an event in the Autocomplete), clicks the reset button and then clicks the input again, the list is filtered to just the previously selected item. This is because the selected item is stored within a selectedItem internal state.
How can I get the reset method to trigger a change within Autocomplete component and clear the selectedItem state?
I've isolated the issue here.
You can use React.useEffect to detect if the user hits the reset button and reset the selected items accordingly in your Autocomplete component
const [inputItems, setInputItems] = useState(options);
const {
inputValue,
...
} = useCombobox({
items: inputItems,
...
});
React.useEffect(() => {
if (!inputValue) {
// user resets value. Reset selected option
setInputItems(options);
}
}, [inputValue, options, setInputItems]);
Live Demo
I have a material-ui Table and have been implementing multi-select functionality on it.
My multi select should behave as follows :
Select checkboxes only appear at the start of a row on hover (when nothing has been selected)
Once one row has been selected, all other checkboxes become permanently visible.
The checkbox in the TableHead will select / deselect all rows in the Table when toggled.
Each row has its own individual unique id.
I maintain a Set called idsOfSelectedRows via a useState hook to keep track of all rows currently selected.
Each TableRow has a Checkbox which looks like this
<Checkbox
className={
idsOfSelectedRows.size === 0 &&
styles.rowSelectionCheckboxStyle
}
onChange={() => handleRowSelectionCheckboxClick}
checked={idsOfSelectedRows.has(row.id)}
/>
and handleRowSelectionCheckboxClick looks like this
const handleRowSelectionCheckboxClick = event => {
const idOfClickedRow = event.target.attributes.getNamedItem("id").value;
//If the checkbox has just become checked then add it to the idOfSelectedRows Set, otherwise remove it.
setIdsOfSelectedRows(
event.target.checked
? new Set(idsOfSelectedRows.add(String(idOfClickedRow)))
: () => {
idsOfSelectedRows.delete(String(idOfClickedRow));
return new Set(idsOfSelectedRows);
}
);
};
My issue is that clicking on the checkboxes on the rows is unresponsive. I can select them all by clicking on the select all Checkbox in the TableHead but clicking on checkboxes in individual rows does not change their state ?
Here's a full CodeSandbox reproducing the exact issue. What do I need to do to make the checkboxes in the rows be toggleable ?
Remove the () => from the onChange assignment for a quick fix.
Why
You're declaring an anonymous inline function, but that function does not call anything (missing () that is syntax to call a function). onChange accepts a function reference. When you give it an inline function, that's the function it will call. The other option is to only pass it the function reference of handleRowSelectionCheckboxClick, and then that function will be called on change instead of the anonymous function middleman.
So your two options are:
onChange={handleRowSelectionCheckboxClick} // Just the reference
OR
onChange={(e) => handleRowSelectionCheckboxClick(e)} // New inline function that calls your function
The second way is unnecessary in most cases. The first is preferred unless you need to pass custom parameters. Here is an example of how it might be useful:
onChange={(e) => handleRowSelectionCheckboxClick(e, id)}
In your sandbox, you map over elements and each gets a change handler. To treat them separately in the handler, you can pass an extra variable to the function like above.
For example, I got your sandbox working by changing the handler and assignment to this:
const handleRowSelectionCheckboxClick = (event, idOfClickedRow) => {
...
onChange={(e) => handleRowSelectionCheckboxClick(e, row.id)}
This line: event.target.attributes.getNamedItem("id").value;
won't give you the required id, since there isn't one passed, change the chekbox like so:
<Checkbox
id={row.id}
onChange={handleRowSelectionCheckboxClick}
checked={idsOfSelectedRows.has(row.id)}
/>
Then, retreive the ID like so:
const idOfClickedRow = event.target.attributes.id.value;
Updated codesandbox:
Like the other answers suggest, change the handleRowSelectionCheckboxClick function call like shown in the example.
If you like your solution with an anonymous function, you should add the (): onChange={() => handleRowSelectionCheckboxClick()}
I have an input type checkbox as follow:
const [is_checked,set_is_checked]= useState(false);
const toggle_payment = () => {
set_is_checked(!is_checked);
console.log(is_checked);
}
return(
<div>
<input checked={is_checked} onChange={toggle_value} type="checkbox"/>
</div>
)
The problem
This seems to work fine, But when I console.log(is_checked) it looks like it prints the previous value. I tried both onChange and onClick but got the same result. What confuses me is that the checkbox is getting checked / unchecked each time I click on the box, but the console.log prints different value than what expected to print, like when I check the box with the mouse click, the box got checked but the console.log prints false
the state update using the updater provided by useState hook is asynchronous, and will not immediately reflect and update but will trigger a re-render
i think that if you console.log() outside the function you might gonna see the changes of the is_checked
This is due to the way state management works in React. A call to a state setter function (in this case set_is_checked) will update the value, but that updated value is available on the next render. When you call console.log below set_is_checked, you are still referencing the old value prior to the state being set.
I have the following problem: I'm working on a react app and I have a div, which contains multiple span-tags. The value of these span tags are dynamically changed and whenever a change of these values occured, I'd like to trigger an animation. While the values are changing without any problems, the animation only triggers during the first initial load. Afterward it fails to trigger. Is there any way I can tell or force my app to trigger the animation when the value of the div-container is changed?
Here is a shortened example of my code:
<div className="animation">
<span>{value}</span>
<span>{value2}</span>
</div>
I don't know how your values are structured but here's my recommendation
Make an animated span component and get the value as a prop.
Then whenever that value changes, The span component will re-render and you will see the animation.
Put your value and value2 in to the state, and then change the state value and your component will re-render.
Like this:
constructor() {
super();
this.state = {
value: 'animation',
value2: 'animation'
};
}
changeAnimation() {
this.setState({
value: 'animation2',
value2: 'animation2'
})
}
I have a dropdown I want to be pre-selected when the data is available. However there appears to be no real chance for that?
Since I am waiting for a change in state for a particular value using that value as the value= causes the selections to be unselectable, while using it as a defaultValue= causes the UI to not recognize the value unless a change to the element has been made meaning if the user decides to go with the default choice it wouldn't be passed up the to the API I am trying to pass it up to.
Is there a way to dynamically change a select box after the dom is ready after the components mounted and when a state is changed?
It's a bit difficult without seeing the code, but have you tried setting the value into the React component's state and rendering that instead? You can also read the state's value instead of the DropDown's.
getInitialState: function () {
return {
dropDownSelection: "some default value"
};
},
handleSelectionChanged: function (e) {
this.setState({
dropDownSelection: e.target.value
});
},
render: function () {
return (
//...
<select className="form-control" value={this.state.dropDownSelection} onChange={this.handleSelectionChanged}>
//...
</select>
);
}