Skip to content

Commit

Permalink
Create useBindingState
Browse files Browse the repository at this point in the history
  • Loading branch information
littensy committed Apr 22, 2023
1 parent 57b2abc commit 10350f5
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,8 @@ export * from "./utils/testez";
export * from "./utils/motor";
export * from "./utils/binding";

export * from "./use-binding-effect";
export * from "./use-binding-state";
export * from "./use-camera";
export * from "./use-memoized-callback";
export * from "./use-previous";
35 changes: 35 additions & 0 deletions src/use-binding-state/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
## 🪝 useBindingState

```ts
function useBindingState<T>(binding: T | Roact.Binding<T>): T;
```

Returns the value of the given binding. When the binding updates, the component will be re-rendered with the new value.

If not passed a valid binding, the value passed to the hook will be returned.

### 📕 Parameters

- `binding` - The binding to subscribe to.

### 📗 Returns

- The value of the binding.

### 📘 Example

```tsx
interface Props {
visible: boolean | Roact.Binding<boolean>;
}

export default function Component({ visible }: Props) {
const isVisible = useBindingState(visible);

useEffect(() => {
print("Visible changed to", isVisible);
}, [isVisible]);

return <frame Visible={visible} />;
}
```
1 change: 1 addition & 0 deletions src/use-binding-state/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./use-binding-state";
39 changes: 39 additions & 0 deletions src/use-binding-state/use-binding-state.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/// <reference types="@rbxts/testez/globals" />

import { createBinding } from "@rbxts/roact";
import { renderHook } from "../utils/testez";
import { useBindingState } from "./use-binding-state";

export = () => {
it("should return the current value", () => {
const [binding] = createBinding(0);
const { result } = renderHook(() => useBindingState(binding));
expect(result.current).to.equal(0);
});

it("should update the value when the binding updates", () => {
const [binding, setBinding] = createBinding(0);
const { result } = renderHook(() => useBindingState(binding));
expect(result.current).to.equal(0);
setBinding(1);
expect(result.current).to.equal(1);
});

it("should not update the value after unrelated rerender", () => {
const [binding] = createBinding(0);
const { result, rerender } = renderHook(() => useBindingState(binding));
expect(result.current).to.equal(0);
rerender();
expect(result.current).to.equal(0);
});

it("should not update the value if the binding changes", () => {
const [binding] = createBinding(0);
const { result, rerender } = renderHook(({ binding }) => useBindingState(binding), {
initialProps: { binding },
});
expect(result.current).to.equal(0);
rerender({ binding: createBinding(1)[0] });
expect(result.current).to.equal(0);
});
};
16 changes: 16 additions & 0 deletions src/use-binding-state/use-binding-state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Binding } from "@rbxts/roact";
import { useState } from "@rbxts/roact-hooked";
import { useBindingEffect } from "../use-binding-effect";
import { getBindingValue } from "../utils/binding";

/**
* Returns the value of a binding. If the binding updates, the component will
* be re-rendered. Non-binding values will be returned as-is.
* @param binding The binding to get the value of.
* @returns The value of the binding.
*/
export function useBindingState<T>(binding: T | Binding<T>): T {
const [value, setValue] = useState(() => getBindingValue(binding));
useBindingEffect(binding, setValue);
return value;
}

0 comments on commit 10350f5

Please sign in to comment.