Skip to content

Commit c4bbf8c

Browse files
committed
fix(mandatory-scope-binding): further improve scopeless invokation detection
1 parent 8300500 commit c4bbf8c

5 files changed

Lines changed: 347 additions & 175 deletions

File tree

src/rules/mandatory-scope-binding/mandatory-scope-binding.md

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,40 @@ description: Forbid Event and Effect usage without useUnit in React components
44

55
# effector/mandatory-scope-binding
66

7-
Forbids `Event` and `Effect` usage without `useUnit` in React components.
8-
This ensures `Fork API` compatibility and allows writing isomorphic code for SSR apps.
7+
Forbids `EventCallable` and `Effect` usage without `useUnit` in React. This ensures `Fork API` compatibility for easy testing via `fork()` and running isomorphic code in SSR/SSG apps.
98

109
```tsx
1110
const increment = createEvent()
1211

1312
// 👍 Event usage is wrapped with `useUnit`
1413
const GoodButton = () => {
15-
const incrementEvent = useUnit(increment)
14+
const onClick = useUnit(increment)
1615

17-
return <button onClick={incrementEvent}>+</button>
16+
return <button onClick={onClick /* bound to Scope */}>+</button>
1817
}
1918

2019
// 👎 Event is not wrapped with `useUnit` - component is not suitable for isomorphic SSR app
2120
const BadButton = () => {
2221
return <button onClick={increment}>+</button>
2322
}
2423
```
24+
25+
This rule doesn't enforce using a `Scope` by itself – your app will run scopeless unless configured. However, when you do, `mandatory-scope-binding` rule ensures no additional work needed to ensure `Scope` is not lost.
26+
27+
### Custom Hooks and Components
28+
29+
You don't need `useUnit` everywhere – passing a unit straight to a custom `effector` aware hook or component whose signature openly declares a unit-typed parameter is fine. It is assumed the receiver takes responsibility of binding event to `Scope` via `useUnit`.
30+
31+
```tsx
32+
type Props = { event: EventCallable<void> }
33+
const PressButton = ({ event }: Props) => <button onClick={useUnit(event) /* <== bound to Scope */}>click</button>
34+
35+
// 👍 PressButton's `event` is typed as a Unit – just pass it in, no issue
36+
const Page = () => <PressButton event={pressed} />
37+
```
38+
39+
::: warning Receiver Type Guarantee
40+
A receiver declared as plain `() => void` does not count – TypeScript accepts the unit structurally, but the consumer hasn't promised to bind it to `Scope`.
41+
42+
Either explicitly type the parameter as a Unit (`EventCallable` / `Effect`) and opt-in to provide this guarantee, or wrap with `useUnit` at the call site.
43+
:::

0 commit comments

Comments
 (0)