-
Notifications
You must be signed in to change notification settings - Fork 6
Bang Tips and Tricks
ngx-bang
is designed (and required) to be used mainly as Local State Management due to how we need ChangeDetectorRef
to invalidate our snapshot.
Technical wise, putting state()
in a global Injectable
(eg: providedIn: 'root'
) isn't that different from putting it in a local Injectable
. However, the following rules should apply:
- Never read from Global
ngx-bang
on the template. - Never use
state
from Globalngx-bang
with*stateful
- Derive local component states (view models) from Global
ngx-bang
withderive()
then usederived
with*stateful
@Injectable({providedIn: 'root'})
export class AuthStore {
state = state<{ user: User | null }>({user: null});
}
@Component({
template: `
<ng-container *stateful="navbarState; let snapshot">
{{snapshot.username}}
</ng-container>
`
})
export class NavbarComponent {
navbarState = derive({
username: get => get(this.authStore.state).user?.name
});
constructor(private authStore: AuthStore) {
}
}
ngx-bang
works with both mutability and immutability. If you prefer to use mutability approach, you should build your APIs in a way that work with Index rather than a Unique ID
@Component({
template: `
<todo-list
[todos]="snapshot.todos"
(toggleComplete)="onToggle($event)"
></todo-list>
`
})
export class TodoComponent {
state = state<{todos: Todo[]}>({todos: []});
// 👇 use index here instead of some unique ID
onToggle(index: number) {
this.state.todos[index].completed = !snapshot(this.state).todos[index].completed
}
}
You can split StateProxy
from an original StateProxy
interface State {
products: Product[];
selectedProducts: Record<string, Product>;
}
const state = state<ProductState>({
products: [],
selectedProducts: {}
});
const productsState = state.products; // StateProxy<Product>[];
const selectedProductsState = state.selectedProducts; // StateProxy<Record<string, Product>>;
You can also combine them
interface ProductState {
products: Product[];
selectedProducts: Record<string, Product>;
}
const productsState = state<ProductState['products']>([]);
const selectedProductsState = state<ProductState['selectedProducts']>({});
const state = state({
products: productsState as ProductState['products'],
selectedProducts: selectedProductsState as ProductState['selectedProducts']
});
Sometimes you would like to reset the StateProxy
to its initial state. This is not straightforward because StateProxy
needs to be reconstructed in the case of reset.
It is best to create a utility function with some cloneDeep
logic.
const initialObj = {
text: 'hello',
arr: [1, 2, 3],
obj: { a: 'b' },
}
const state = state(initialObj);
const reset = () => {
const resetObj = _.cloneDeep(initialObj);
Object.keys(resetObj).forEach((key) => {
state[key] = resetObj[key]
});
}