So I have been trying to accomplish the idea that whenever the user clicks any row in the DetailsList the Button gets enabled and when the user clicks outside the selectionzone the Button gets disabled.
This is my code
import { DetailsList, SelectionMode, Selection, ISelection, initializeIcons, PrimaryButton } from '@fluentui/react'
import {useMemo } from 'react'
import { useBoolean } from '@uifabric/react-hooks'
interface ICurrency {
type: string,
amount: number
}
function App() {
initializeIcons()
const [isBtn, { setTrue: disableBtn, setFalse: enableBtn }] = useBoolean(true)
const items: ICurrency[] = [
{
type: 'INR',
amount: 20
},
{
type: 'USD',
amount: 50
},
{
type: 'GBP',
amount: 70
}
]
const selection: ISelection = useMemo(() => new Selection(
{
onSelectionChanged: ()=>{
if(selection.getSelectedCount() > 0){
enableBtn()
}else{
disableBtn()
}
}
}
), [items])
return (
<div className="App">
<PrimaryButton text="Button" disabled={isBtn}/>
<DetailsList
items={items} selectionMode={SelectionMode.single}
selection={selection}
/>
</div>
);
}
export default App;
I even used useMemo and kept on banging my head but the problem persists where clicking any row the state is lost and the button is not enabled. I have already tried storing the state of selection also, count, everything but it seems I'm missing out on something essential or fundamental for the implementation
You need to memoize items
because on each render it's being re-assigned and considered a new array which causes your selection
to change because it relies on items
as a useMemo
dependency. On each state update the selection will reset.
So one way you can fix this is by moving the items out of the function so that it holds reference instead of creating a new items array on each render.
const items = [
{
type: "INR",
amount: 20
},
{
type: "USD",
amount: 50
},
{
type: "GBP",
amount: 70
}
];
function App() {
// code
}
or by using useMemo
on those items:
const items = useMemo(() => [
{
type: "INR",
amount: 20
},
{
type: "USD",
amount: 50
},
{
type: "GBP",
amount: 70
}
],[]);
Also I see you have an error, the initializeIcons
should only be called once. So that should probably be placed in useEffect
:
useEffect(() => {
initializeIcons();
},[])
The final code sample should look like this:
import {
DetailsList,
SelectionMode,
Selection,
ISelection,
initializeIcons,
PrimaryButton
} from "@fluentui/react";
import { useMemo, useEffect } from "react";
import { useBoolean } from "@uifabric/react-hooks";
const items = [
{
type: "INR",
amount: 20
},
{
type: "USD",
amount: 50
},
{
type: "GBP",
amount: 70
}
];
function App() {
useEffect(() => {
initializeIcons();
}, []);
const [isBtn, { setTrue: disableBtn, setFalse: enableBtn }] = useBoolean(
true
);
const selection = useMemo(
() =>
new Selection({
onSelectionChanged: () => {
if (selection.getSelectedCount() > 0) {
enableBtn();
} else {
disableBtn();
}
}
}),
[items]
);
return (
<div className="App">
<PrimaryButton text="Button" disabled={isBtn} />
<DetailsList
items={items}
selectionMode={SelectionMode.single}
selection={selection}
/>
</div>
);
}
export default App;