Как отобразить товары из магазина redux в приложении angular5?

У меня есть компонент angular5, который я пытаюсь соединить с магазином reduxstore, он выглядит так:

import { Component } from '@angular/core';
import { NgRedux, select, DevToolsExtension } from '@angular-redux/store';
import { TodoActions } from './actions';
import { AppState, INITIAL_STATE, rootReducer } from './store';
import {Observable} from "rxjs/Observable";

@Component({
  selector: 'app-root',
  template: `    
    <input type="text" #edit />
    <button (click)="actions.add({data:edit,action:'ADD'})">add</button>
    <p>The list is:</p>
    <ul>
      <li *ngFor="let item of (items | async)">
        {{item}}
      </li>
    </ul>
  `,
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';
  @select() readonly items$: Observable<string[]>;

  constructor(
    ngRedux: NgRedux<AppState>,
    devTools: DevToolsExtension,
    private actions: TodoActions) {

    ngRedux.configureStore(
      rootReducer,
      INITIAL_STATE,
      null,
      devTools.isEnabled() ? [ devTools.enhancer() ] : []);
  }
}

Проблема в том, что я не могу отображать элементы в списке. Вот корневой редуктор:

import {Action} from 'redux';
import {TodoActions} from './actions';

export interface AppState {
  items: string[];
}
export const INITIAL_STATE: AppState = {items: []};

export function rootReducer(state: AppState, action: Action): AppState {
  switch (action.type) {
    case TodoActions.ADD:
      var newstate = state;
      newstate.items.push(action.data.data.value);
      return newstate;
  }
  ;

default:
  return state;
}
}

Как я могу отобразить элементы? Похоже, что первый элемент добавляется в состояние с помощью приставки. Здесь также githublink

1 ответ

Решение

Это выглядит не совсем правильно:

  var newstate = state;
  newstate.items.push(action.data.data.value);
  return newstate;

Вы на самом деле не создаете новый массив или копию: оба newstate а также state один и тот же массив, так что вам, вероятно, лучше вернуть новый массив с мелким клонированием:

export function rootReducer(state: AppState, action): AppState {
  switch (action.type) {
    case TodoActions.ADD:
      return {
        ...state,
        items: [
          ...state.items,
          action.data.value
        ]
      }

    default:
      return state;
  }
}

Вы можете заметить, что я отключил спецификатор типа action, Я не уверен, что имеет смысл указать Action как тип для действия, в большинстве примеров кода, которые я видел, он прошел нетипизированный так:

export function rootReducer(state: AppState, action): AppState {

Это позволит избежать жалоб TS на отсутствие data по типу Action, Кроме того, вы можете определить тип настраиваемого действия для каждого написанного вами редуктора.

Как только вы пройдете через это, я думаю, что вы не видите никаких элементов, потому что вы называете массив items$ в @select декоратор. Так:

@Component({
  selector: 'app-root',
  template: `    
    <input type="text" #edit />
    <button (click)="actions.add({value:edit.value,action:'ADD'})">add</button>
    <p>The list is:</p>
    <ul>
      <li *ngFor="let item of (items$ | async)">
        {{item}}
      </li>
    </ul>
  `,
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';
  @select() readonly items$: Observable<string[]>;

работает лучше. Примечание. Я немного подправил определение кнопки, чтобы не пропускать весь ввод, так как вам нужно только value,

Другие вопросы по тегам