DetailsList перерисовывается и, следовательно, теряет свое состояние
Итак, я пытался реализовать идею о том, что всякий раз, когда пользователь щелкает любую строку в DetailsList, кнопка включается, а когда пользователь щелкает вне зоны выбора, кнопка отключается.
Это мой код
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;
Я даже использовал useMemo и продолжал биться головой, но проблема сохраняется, когда при нажатии любой строки состояние теряется, а кнопка не активна. Я уже пробовал сохранить состояние выбора, подсчитать, все, но, похоже, я упускаю что-то важное или фундаментальное для реализации
2 ответа
Вам нужно мемоизировать, потому что при каждом рендеринге он переназначается и считается новым массивом, который вызывает ваш
selection
изменить, потому что он полагается на
items
как зависимость. При каждом обновлении состояния выбор сбрасывается.
Таким образом, вы можете исправить это, переместив элементы из функции, чтобы она содержала ссылку вместо создания массива новых элементов при каждом рендеринге.
const items = [
{
type: "INR",
amount: 20
},
{
type: "USD",
amount: 50
},
{
type: "GBP",
amount: 70
}
];
function App() {
// code
}
или используя
useMemo
по этим пунктам:
const items = useMemo(() => [
{
type: "INR",
amount: 20
},
{
type: "USD",
amount: 50
},
{
type: "GBP",
amount: 70
}
],[]);
Также я вижу, что у вас ошибка,
initializeIcons
следует вызывать только один раз. Так что это, вероятно, следует поместить в
useEffect
:
useEffect(() => {
initializeIcons();
},[])
Окончательный пример кода должен выглядеть так:
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;
Принятый ответ содержит правильное обоснование проблемы. Я просто хотел опубликовать свое решение. Мне просто нужно было сохранить состояние предметов
import { DetailsList, SelectionMode, Selection, initializeIcons, PrimaryButton } from '@fluentui/react'
import { useEffect, useState } from 'react'
import { useBoolean } from '@uifabric/react-hooks'
interface ICurrency {
type: string,
amount: number
}
function App() {
useEffect(() => {
initializeIcons();
}, []);
const [isBtn, { setTrue: disableBtn, setFalse: enableBtn }] = useBoolean(true)
let _selection = new Selection({
onSelectionChanged: () => {
if (_selection.getSelectedCount() > 0) {
enableBtn()
} else {
disableBtn()
}
}
});
let _initialItems: ICurrency[] = [
{
type: 'INR',
amount: 20
},
{
type: 'USD',
amount: 50
},
{
type: 'GBP',
amount: 70
}
]
const [items, setItems] = useState(_initialItems)
return (
<>
<PrimaryButton text="Button" disabled={isBtn} />
<DetailsList
items={items}
selection={_selection}
selectionMode={SelectionMode.single}
/>
</>
);
}
export default App;
Теперь скажите, если элементы поступают из некоторых свойств или некоторого управления состоянием, тогда просто используйте setItems внутри useEffect и установите зависимость как этот источник