最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Simple state management in Angular? - Stack Overflow

programmeradmin1浏览0评论

I'm learning Angular from the very beginning, and ing from React, I can't find a way to manage a simple state in Angular. It's a simple todo app, and my strategy is to create a Todos array in todo.service.ts

@Injectable()
export class TodoService {
  todos: Todo[] = [
    { id: 0, title: 'Cooking', pleted: false }
]
  nextId: number = 1;
  constructor() { }
  public getTodos(): Todo[] {
    return this.todos;
  }
  public addTodo(title: string): any {
    this.newTodo = new Todo({ id: this.nextId, title, pleted: false })
    this.todos.push(this.newTodo);
    this.newTodo = new Todo();
    this.nextId++
  }
  public deleteTodo(chosenTodo: Todo): any {
    this.todos = this.todos.filter(todo => todo.id !== chosenTodo.id)
  }
}

Now on the ListingComponent, I want to get all Todos, and then pass it down to ListingItemComponent, as such

todos: Todo[] = []
  todoTitle: string = '';
  constructor(private todoService: TodoService) { }
  ngOnInit(): void {
    this.todos = this.todoService.getTodos();
    this.todoTitle = 'Do Something';
  }

  addTodo() {
    this.todoService.addTodo(this.todoTitle);
  }
<div *ngFor="let todo of todos">
  <todo-listing-item [todo]="todo"></todo-listing-item>
</div>
/* This just adds a todo with title 'Do Something' for testing */
<button (click)="addTodo()">Add Todo</button>

Finally in ListingItemComponent

  @Input() todo: Todo
  constructor(private todoService: TodoService) { }

  ngOnInit(): void {
  }
  deleteTodo(): void {
    this.todoService.deleteTodo(this.todo)
  }
<h1>{{todo.title}}</h1>
<button (click)="deleteTodo()">Delete Todo</button>

Now the ponent has no error, and I made sure to declare everything, but it's not working. Clicking the button won't change anything. After digging in, I changed the ListingComponent into "let todo of todoService.getTodos()", and remove the todos in the ts file along with the ngOnInit, and somehow it works. My guessing is that the ListingComponent doesn't know that the todos array has changed, and so it's not rerendering?

  1. So if I was to initialize the todos in the ngOnInit like I did before, do I need some other life-cycle to listen to the change of todos?
  2. If many ponents need the todos array, should I write ngOnInit(): void { this.todos = this.todoService.getTodos();} on every single one of them? And if one ponent changes their todos, can other ponents listen and rerender as well?

    Thank you for reading. In React I would just create a global state, along with the functions, and pass it as props down to every child. But I can't wrap my head around managing state in Angular. Is it because I'm thinking in React, while I should not?

I'm learning Angular from the very beginning, and ing from React, I can't find a way to manage a simple state in Angular. It's a simple todo app, and my strategy is to create a Todos array in todo.service.ts

@Injectable()
export class TodoService {
  todos: Todo[] = [
    { id: 0, title: 'Cooking', pleted: false }
]
  nextId: number = 1;
  constructor() { }
  public getTodos(): Todo[] {
    return this.todos;
  }
  public addTodo(title: string): any {
    this.newTodo = new Todo({ id: this.nextId, title, pleted: false })
    this.todos.push(this.newTodo);
    this.newTodo = new Todo();
    this.nextId++
  }
  public deleteTodo(chosenTodo: Todo): any {
    this.todos = this.todos.filter(todo => todo.id !== chosenTodo.id)
  }
}

Now on the ListingComponent, I want to get all Todos, and then pass it down to ListingItemComponent, as such

todos: Todo[] = []
  todoTitle: string = '';
  constructor(private todoService: TodoService) { }
  ngOnInit(): void {
    this.todos = this.todoService.getTodos();
    this.todoTitle = 'Do Something';
  }

  addTodo() {
    this.todoService.addTodo(this.todoTitle);
  }
<div *ngFor="let todo of todos">
  <todo-listing-item [todo]="todo"></todo-listing-item>
</div>
/* This just adds a todo with title 'Do Something' for testing */
<button (click)="addTodo()">Add Todo</button>

Finally in ListingItemComponent

  @Input() todo: Todo
  constructor(private todoService: TodoService) { }

  ngOnInit(): void {
  }
  deleteTodo(): void {
    this.todoService.deleteTodo(this.todo)
  }
<h1>{{todo.title}}</h1>
<button (click)="deleteTodo()">Delete Todo</button>

Now the ponent has no error, and I made sure to declare everything, but it's not working. Clicking the button won't change anything. After digging in, I changed the ListingComponent into "let todo of todoService.getTodos()", and remove the todos in the ts file along with the ngOnInit, and somehow it works. My guessing is that the ListingComponent doesn't know that the todos array has changed, and so it's not rerendering?

  1. So if I was to initialize the todos in the ngOnInit like I did before, do I need some other life-cycle to listen to the change of todos?
  2. If many ponents need the todos array, should I write ngOnInit(): void { this.todos = this.todoService.getTodos();} on every single one of them? And if one ponent changes their todos, can other ponents listen and rerender as well?

    Thank you for reading. In React I would just create a global state, along with the functions, and pass it as props down to every child. But I can't wrap my head around managing state in Angular. Is it because I'm thinking in React, while I should not?

Share Improve this question asked May 10, 2020 at 2:20 Free MeFree Me 1954 silver badges12 bronze badges 9
  • You got the part about shared services right. If you want multiple ponents to observe this change, you can use Observables to notify all the subscribes of this change. angular.io/guide/observables-in-angular – sinanspd Commented May 10, 2020 at 2:27
  • As mentioned above, you need to use Observables. Here's a good tutorial dev.to/avatsaev/… – xandermonkey Commented May 10, 2020 at 2:28
  • 1 If you're looking for more robust state management, I'd remend ngrx.io – xandermonkey Commented May 10, 2020 at 2:28
  • @xandermonkey yes I've heard about ngrx, but this is my first ever app, so I want to stay away from libraries for now, but i'll definitely check it out. – Free Me Commented May 10, 2020 at 2:30
  • 1 @FreeMe Correct. you shouldn't need any extra life cycle hooks. Although they are NOT the same thing, you can think of the behaviour similar to plain JS event listeners, it doesn't really matter what sub-scope you initialize them, they will get executed. You would still have a todos array in your ponent. Inside your subscribe you would mutate that array and your ngFor would pick up that change – sinanspd Commented May 10, 2020 at 2:37
 |  Show 4 more ments

4 Answers 4

Reset to default 3

Let me first say that I'm a huge fan of NGRX and the pattern, and I suggest you make this part of your learning path. However, if you're looking for simple state management than a simple Observable will do the trick.

I created a stack overflow to illustrate the technique using the code you provided: https://stackblitz./edit/angular-ivy-kfw1sd. In this demonstration, I'm leveraging BehaviorSubject which is a special type of observable.

In closing, do your best to avoid .subscribe() and use the async pipe instead.

Hope this helps, Isaac

If you want to have a simple global state, you can start using Shared Services, obviously it will be only for learning purposes, because if you want to use in a real project, you can use Shared Services, but also, you would need Facade or other Design Patterns.

Main advantage using Facade is that you can migrate to NgRx easier.

I have an example using API + State + Base Architecture: https://github./cmandamiento/angular-architecture-base

Feel free to reach me out.

Indeed you do not always need to add another Library to manage state in Angular. Angular es with RxJS out of the box...

All the well known state management libraries use RxJS/BehaviorSubject internally. This article shows how to write a simple DIY state management Class which can be extended by Angular services.

Simple yet powerful state management in Angular with RxJS

This solution is also based on RxJS/BehaviorSubject.

Maybe it can be useful for you. The code example in the article is a Todo App :)

Disclaimer: I'm the author of the library

ng-simple-state

Simple state management in Angular with only Services and RxJS

  • See the stackblitz demo.
  • See the source code.
发布评论

评论列表(0)

  1. 暂无评论