适用场景:
- 多个组件对同一个状态进行多次修改,代码无需耦合在一起
举个例子
- 写一个table公共组件,有一份列配置。 新增一列checkbox。
export function useRowSelection(props: Props | undefined) {
const { store, columnOptionsAtom } = useData()
useLayoutEffect(() => {
if (!props) {
return
}
return store.setter(columnOptionsAtom, (_getter, prev) => {
const option: ColumnType = {
title: props.title,
width: props.width,
render: props.render || render,
fixed: props.fixed,
}
return [option, ...prev]
})
}, [props])
}
- 例子2
有一状态style ,初始值为{color:"gray"}。
点击组件A,add按钮 {color:"red"} cancel按钮 取消{color:"red"}状态
点击组件B, add按钮 {color:"blue"} cancel按钮 取消{color:"blue"}状态
const styleIncrementAtom = incrementAtom<CSSProperties>({ color: 'gray' })
A组件
function A() {
const [incrementStateFn, cleanStateFn] = useIncrementAtom(styleIncrementAtom)
return (
<div>
<button
data-testid="btn-red"
onClick={() => {
incrementStateFn((_getter, prevReturn) => {
return {
...prevReturn,
color: 'red',
}
})
}}
>
color red
</button>
<button
data-testid="btn-cancel-red"
onClick={() => {
cleanStateFn()
}}
>
cancel color red
</button>
</div>
)
}
})
})
B组件
function B() {
const [incrementStateFn, cleanStateFn] = useIncrementAtom(styleIncrementAtom)
const { color } = useAtomValue(styleIncrementAtom)
return (
<div>
<button
data-testid="btn-blue"
onClick={() => {
incrementStateFn((_getter, prevReturn) => {
return {
...prevReturn,
color: 'blue',
}
})
}}
>
color red
</button>
<button
data-testid="btn-cancel-blue"
onClick={() => {
cleanStateFn()
}}
>
cancel color red
</button>
<div data-testid="result">{color}</div>
</div>
)
}
App
function App() {
return (
<div data-testid="app">
<A />
<B />
</div>
)
}
测试
const { baseElement } = render(<App />)
await screen.findByTestId('app')
expect(queryByTestId(baseElement, 'result')).toBeInTheDocument()
expect(queryByTestId(baseElement, 'result')?.textContent).toBe('gray')
await userEvent.click(screen.getByTestId('btn-red'))
expect(queryByTestId(baseElement, 'result')?.textContent).toBe('red')
await userEvent.click(screen.getByTestId('btn-blue'))
expect(queryByTestId(baseElement, 'result')?.textContent).toBe('blue')
await userEvent.click(screen.getByTestId('btn-cancel-blue'))
expect(queryByTestId(baseElement, 'result')?.textContent).toBe('red')
await userEvent.click(screen.getByTestId('btn-cancel-red'))
expect(queryByTestId(baseElement, 'result')?.textContent).toBe('gray')
await userEvent.click(screen.getByTestId('btn-blue'))
expect(queryByTestId(baseElement, 'result')?.textContent).toBe('blue')