-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(useSelections): support object array
- Loading branch information
Showing
7 changed files
with
463 additions
and
118 deletions.
There are no files selected for viewing
271 changes: 171 additions & 100 deletions
271
packages/hooks/src/useSelections/__tests__/index.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,125 +1,196 @@ | ||
import { act, renderHook } from '@testing-library/react'; | ||
import useSelections from '../index'; | ||
import type { Options } from '../index'; | ||
|
||
const data = [1, 2, 3]; | ||
const _data = [1, 2, 3]; | ||
const _selected = [1]; | ||
const _selectedItem = 1; | ||
|
||
const setup = <T>(items: T[], defaultSelected?: T[]) => { | ||
return renderHook(() => useSelections(items, defaultSelected)); | ||
const _dataObj = [{ id: 1 }, { id: 2 }, { id: 3 }]; | ||
const _selectedObj = [{ id: 1 }]; | ||
const _selectedItemObj = { id: 1 }; | ||
|
||
const setup = <T>(items: T[], options?: T[] | Options<T>) => { | ||
return renderHook(() => useSelections(items, options)); | ||
}; | ||
|
||
interface CaseCallback<T = number | object> { | ||
(data: T[], selected: T[], selectedItem: T): void; | ||
} | ||
|
||
const runCaseCallback = ( | ||
dataCallback: CaseCallback<number>, | ||
objDataCallback: CaseCallback<object>, | ||
) => { | ||
dataCallback(_data, _selected, _selectedItem); | ||
objDataCallback(_dataObj, _selectedObj, _selectedItemObj); | ||
}; | ||
|
||
describe('useSelections', () => { | ||
it('defaultSelected should work correct', () => { | ||
const { result } = setup(data, [1]); | ||
expect(result.current.selected).toEqual([1]); | ||
expect(result.current.isSelected(1)).toBe(true); | ||
const caseCallback: CaseCallback = (data, selected, selectedItem) => { | ||
const { result } = setup(data, { | ||
defaultSelected: selected, | ||
itemKey: 'id', | ||
}); | ||
|
||
expect(result.current.selected).toEqual(selected); | ||
expect(result.current.isSelected(selectedItem)).toBe(true); | ||
}; | ||
|
||
runCaseCallback(caseCallback, caseCallback); | ||
}); | ||
|
||
it('select and unSelect should work correct', () => { | ||
const { result } = setup(data, [1]); | ||
const { unSelect, select } = result.current; | ||
act(() => { | ||
unSelect(1); | ||
}); | ||
expect(result.current.selected).toEqual([]); | ||
expect(result.current.isSelected(1)).toBe(false); | ||
expect(result.current.allSelected).toBe(false); | ||
act(() => { | ||
select(1); | ||
}); | ||
expect(result.current.selected).toEqual([1]); | ||
expect(result.current.isSelected(1)).toBe(true); | ||
expect(result.current.allSelected).toBe(false); | ||
const caseCallback: CaseCallback = (data, selected, selectedItem) => { | ||
const { result } = setup(data, { | ||
defaultSelected: selected, | ||
itemKey: 'id', | ||
}); | ||
const { unSelect, select } = result.current; | ||
|
||
act(() => { | ||
unSelect(selectedItem); | ||
}); | ||
expect(result.current.selected).toEqual([]); | ||
expect(result.current.isSelected(selectedItem)).toBe(false); | ||
expect(result.current.allSelected).toBe(false); | ||
|
||
act(() => { | ||
select(selectedItem); | ||
}); | ||
expect(result.current.selected).toEqual(selected); | ||
expect(result.current.isSelected(selectedItem)).toBe(true); | ||
expect(result.current.allSelected).toBe(false); | ||
}; | ||
|
||
runCaseCallback(caseCallback, caseCallback); | ||
}); | ||
|
||
it('toggle should work correct', () => { | ||
const { result } = setup(data); | ||
const { toggle } = result.current; | ||
act(() => { | ||
toggle(1); | ||
}); | ||
expect(result.current.selected).toEqual([1]); | ||
expect(result.current.isSelected(1)).toBe(true); | ||
expect(result.current.allSelected).toBe(false); | ||
act(() => { | ||
toggle(1); | ||
}); | ||
expect(result.current.selected).toEqual([]); | ||
expect(result.current.isSelected(1)).toBe(false); | ||
expect(result.current.allSelected).toBe(false); | ||
const caseCallback: CaseCallback = (data, selected, selectedItem) => { | ||
const { result } = setup(data, { | ||
itemKey: 'id', | ||
}); | ||
const { toggle } = result.current; | ||
|
||
act(() => { | ||
toggle(selectedItem); | ||
}); | ||
expect(result.current.selected).toEqual(selected); | ||
expect(result.current.isSelected(selectedItem)).toBe(true); | ||
expect(result.current.allSelected).toBe(false); | ||
|
||
act(() => { | ||
toggle(selectedItem); | ||
}); | ||
expect(result.current.selected).toEqual([]); | ||
expect(result.current.isSelected(selectedItem)).toBe(false); | ||
expect(result.current.allSelected).toBe(false); | ||
}; | ||
|
||
runCaseCallback(caseCallback, caseCallback); | ||
}); | ||
|
||
it('selectAll and unSelectAll should work correct', async () => { | ||
const { result } = setup(data); | ||
const { selectAll, unSelectAll } = result.current; | ||
|
||
expect(result.current.noneSelected).toBe(true); | ||
act(() => { | ||
selectAll(); | ||
}); | ||
expect(result.current.selected).toEqual([1, 2, 3]); | ||
expect(result.current.allSelected).toBe(true); | ||
expect(result.current.noneSelected).toBe(false); | ||
expect(result.current.partiallySelected).toBe(false); | ||
|
||
act(() => { | ||
unSelectAll(); | ||
}); | ||
expect(result.current.selected).toEqual([]); | ||
expect(result.current.allSelected).toBe(false); | ||
expect(result.current.noneSelected).toBe(true); | ||
expect(result.current.partiallySelected).toBe(false); | ||
const caseCallback: CaseCallback = (data) => { | ||
const { result } = setup(data, { | ||
itemKey: 'id', | ||
}); | ||
const { selectAll, unSelectAll } = result.current; | ||
|
||
expect(result.current.noneSelected).toBe(true); | ||
act(() => { | ||
selectAll(); | ||
}); | ||
expect(result.current.selected).toEqual(data); | ||
expect(result.current.allSelected).toBe(true); | ||
expect(result.current.noneSelected).toBe(false); | ||
expect(result.current.partiallySelected).toBe(false); | ||
|
||
act(() => { | ||
unSelectAll(); | ||
}); | ||
expect(result.current.selected).toEqual([]); | ||
expect(result.current.allSelected).toBe(false); | ||
expect(result.current.noneSelected).toBe(true); | ||
expect(result.current.partiallySelected).toBe(false); | ||
}; | ||
|
||
runCaseCallback(caseCallback, caseCallback); | ||
}); | ||
|
||
it('toggleAll should work correct', async () => { | ||
const { result } = setup(data); | ||
const { toggleAll } = result.current; | ||
expect(result.current.noneSelected).toBe(true); | ||
act(() => { | ||
toggleAll(); | ||
}); | ||
expect(result.current.selected).toEqual([1, 2, 3]); | ||
expect(result.current.allSelected).toBe(true); | ||
expect(result.current.noneSelected).toBe(false); | ||
expect(result.current.partiallySelected).toBe(false); | ||
|
||
act(() => { | ||
toggleAll(); | ||
}); | ||
expect(result.current.selected).toEqual([]); | ||
expect(result.current.allSelected).toBe(false); | ||
expect(result.current.noneSelected).toBe(true); | ||
expect(result.current.partiallySelected).toBe(false); | ||
const caseCallback: CaseCallback = (data) => { | ||
const { result } = setup(data, { | ||
itemKey: 'id', | ||
}); | ||
const { toggleAll } = result.current; | ||
|
||
expect(result.current.noneSelected).toBe(true); | ||
act(() => { | ||
toggleAll(); | ||
}); | ||
expect(result.current.selected).toEqual(data); | ||
expect(result.current.allSelected).toBe(true); | ||
expect(result.current.noneSelected).toBe(false); | ||
expect(result.current.partiallySelected).toBe(false); | ||
|
||
act(() => { | ||
toggleAll(); | ||
}); | ||
expect(result.current.selected).toEqual([]); | ||
expect(result.current.allSelected).toBe(false); | ||
expect(result.current.noneSelected).toBe(true); | ||
expect(result.current.partiallySelected).toBe(false); | ||
}; | ||
|
||
runCaseCallback(caseCallback, caseCallback); | ||
}); | ||
|
||
it('setSelected should work correct', async () => { | ||
const { result } = setup(data); | ||
const { setSelected } = result.current; | ||
expect(result.current.noneSelected).toBe(true); | ||
act(() => { | ||
setSelected([1]); | ||
}); | ||
expect(result.current.selected).toEqual([1]); | ||
expect(result.current.isSelected(1)).toBe(true); | ||
expect(result.current.noneSelected).toBe(false); | ||
expect(result.current.allSelected).toBe(false); | ||
expect(result.current.partiallySelected).toBe(true); | ||
|
||
act(() => { | ||
setSelected([]); | ||
}); | ||
expect(result.current.selected).toEqual([]); | ||
expect(result.current.isSelected(1)).toBe(false); | ||
expect(result.current.noneSelected).toBe(true); | ||
expect(result.current.allSelected).toBe(false); | ||
expect(result.current.partiallySelected).toBe(false); | ||
|
||
act(() => { | ||
setSelected([1, 2, 3]); | ||
}); | ||
expect(result.current.selected).toEqual([1, 2, 3]); | ||
expect(result.current.isSelected(1)).toBe(true); | ||
expect(result.current.noneSelected).toBe(false); | ||
expect(result.current.allSelected).toBe(true); | ||
expect(result.current.partiallySelected).toBe(false); | ||
const caseCallback: CaseCallback = (data, selected, selectedItem) => { | ||
const { result } = setup(data, { | ||
itemKey: 'id', | ||
}); | ||
const { setSelected } = result.current; | ||
|
||
expect(result.current.noneSelected).toBe(true); | ||
act(() => { | ||
setSelected(selected); | ||
}); | ||
expect(result.current.selected).toEqual(selected); | ||
expect(result.current.isSelected(selectedItem)).toBe(true); | ||
expect(result.current.noneSelected).toBe(false); | ||
expect(result.current.allSelected).toBe(false); | ||
expect(result.current.partiallySelected).toBe(true); | ||
|
||
act(() => { | ||
setSelected([]); | ||
}); | ||
expect(result.current.selected).toEqual([]); | ||
expect(result.current.isSelected(selectedItem)).toBe(false); | ||
expect(result.current.noneSelected).toBe(true); | ||
expect(result.current.allSelected).toBe(false); | ||
expect(result.current.partiallySelected).toBe(false); | ||
|
||
act(() => { | ||
setSelected(data); | ||
}); | ||
expect(result.current.selected).toEqual(data); | ||
expect(result.current.isSelected(selectedItem)).toBe(true); | ||
expect(result.current.noneSelected).toBe(false); | ||
expect(result.current.allSelected).toBe(true); | ||
expect(result.current.partiallySelected).toBe(false); | ||
}; | ||
|
||
runCaseCallback(caseCallback, caseCallback); | ||
}); | ||
|
||
it('legacy parameter should work in <4.0', async () => { | ||
const { result } = setup(_data, _selected); | ||
|
||
expect(result.current.selected).toEqual(_selected); | ||
expect(result.current.isSelected(_selectedItem)).toBe(true); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/** | ||
* title: Object array | ||
* desc: When array items are object, you need to specify the field name for the unique key. | ||
* | ||
* title.zh-CN: 对象数组 | ||
* desc.zh-CN: 数组项是对象时,需要指定唯一 key 的字段名称。 | ||
*/ | ||
|
||
import { Checkbox, Col, Row } from 'antd'; | ||
import React, { useMemo, useState } from 'react'; | ||
import { useSelections } from 'ahooks'; | ||
|
||
export default () => { | ||
const [hideOdd, setHideOdd] = useState(false); | ||
const list = useMemo(() => { | ||
if (hideOdd) { | ||
return [2, 4, 6, 8].map((id) => ({ id })); | ||
} | ||
return [1, 2, 3, 4, 5, 6, 7, 8].map((id) => ({ id })); | ||
}, [hideOdd]); | ||
|
||
const { selected, allSelected, isSelected, toggle, toggleAll, partiallySelected } = useSelections( | ||
list, | ||
{ | ||
defaultSelected: [{ id: 1 }], | ||
itemKey: 'id', | ||
}, | ||
); | ||
|
||
return ( | ||
<div> | ||
<div>Selected: {JSON.stringify(selected)}</div> | ||
<div style={{ borderBottom: '1px solid #E9E9E9', padding: '10px 0' }}> | ||
<Checkbox checked={allSelected} onClick={toggleAll} indeterminate={partiallySelected}> | ||
Check all | ||
</Checkbox> | ||
<Checkbox checked={hideOdd} onClick={() => setHideOdd((v) => !v)}> | ||
Hide Odd | ||
</Checkbox> | ||
</div> | ||
<Row style={{ padding: '10px 0' }}> | ||
{list.map((item) => ( | ||
<Col span={12} key={item.id}> | ||
<Checkbox checked={isSelected(item)} onClick={() => toggle(item)}> | ||
{item.id} | ||
</Checkbox> | ||
</Col> | ||
))} | ||
</Row> | ||
</div> | ||
); | ||
}; |
Oops, something went wrong.