web-dev-qa-db-ja.com

Ngrx-ストアの変更後にセレクターが新しい値を出力しない

次のような状態です。

export interface State {
  modules: Module[];
}

そして、モジュールのインターフェースは次のようなものです:

export interface Module {
  name: string;
  structure: {
    moduleID: string;
    icon: string;
    ...
  };
  data: [{id: string; value: string; }];
}

モジュール内のデータは、入力フィールドとコンボボックスに接続されています。ユーザーが入力フィールドで何かを変更すると、アクションがディスパッチされ、ストアはレデューサーによって指定されたデータオブジェクトの新しいデータ値で更新されます。変更がストアで発生することはすでに確認しました。

Reducerは次のことを行っています。

case fromTitelActions.SET_DATA: {
      const stateCopy = {...state};
      const moduleToChange = getModule(action.payload.nameOfModule, stateCopy.modules);
      action.payload.data.forEach(data => changeElementData(moduleToChange, data.Id, data.value));
      return stateCopy;
    }

特定のデータ値をサブスクライブして変更を検出しようとしています。私のセレクターは次のようになります:

export const getDataElementValue = (moduleName, elementId) => createSelector(getModules,
     modules => {
        const module = modules.find(m => m.name === moduleName);
        const data = module.data.find( d => d.id === elementId);
        return data.value;
});

セレクターにサブスクライブすると、その中の現在の値が取得されますが、レデューサーが特定のデータオブジェクトを更新する回数に関係なく、セレクターが再度起動することはありません。私が見逃しているアイデアはありますか?ありがとう。

6

この問題は、moduleToChangeのプロパティを更新するときに、changeElementData関数が新しいオブジェクトを作成していないことが原因である可能性があります。

私はあなたがこのようなものを持っていると思います:

function changeElementData(moduleToChange, id, value) {
    moduleToChange.elements.forEach((el) => {
       if (el.id == id) el.value = value;
    });
}

次のようなものが必要になります。

case fromTitelActions.SET_DATA: {
    const stateCopy = {...state};
    stateCopy.modules = stateCopy.modules.map((moduleToChange) => {
        if (module.name != action.payload.nameOfModule) return moduleToChange;
        else return action.payload.data.map(data => changeElementData(moduleToChange, data.Id, data.value));
    });
    return stateCopy;
}

function changeElementData(moduleToChange, id, value) {
    let found: boolean = false;
    let newModule = module;
    if (moduleToChange.elements.find((el) => el.id == id)) {
        newModule = {
            ...moduleToChange,
            elements: moduleToChange.elements.map((el) => {
                if (el.id == id) return { ...el, value: value };
                else return el;
            })
        }
    }
    return newModule;
}

状態のオブジェクトのプロパティを更新するときは、常に新しい包含オブジェクトを作成する必要があります。NGRXは単純なオブジェクト等価を使用して、何かが変更されたかどうかを判断し、関連するオブザーバブルを起動するためです。オブジェクトのプロパティを更新しても、オブジェクト自体は以前のバージョンと同じ参照を保持しているため、NGRXは変更されていないと見なします。

8
Mark Hughes