2015-10-24 6 views
7

Próbuję opracować idealny sposób aktualizowania kilku pól najwyższego poziomu w moim drzewie stanu, zachowując jednocześnie dzielone reduktory.Najlepszy sposób na aktualizację powiązanych pól stanu za pomocą dzielonych reduktorów?

Oto proste rozwiązanie, które wymyśliłem.

var state = { 
    fileOrder: [0], 
    files: { 
    0:{ 
     id: 0, 
     name: 'asdf' 
    } 
    } 
}; 

function handleAddFile(state, action) { 
    return {...state, ...{[action.id]:{id: action.id, name: action.name}}}; 
}; 

function addFileOrder(state, action) { 
    return [...state, action.id]; 
} 

// Adding a file should create a new file, and add its id to the fileOrder array. 
function addFile(state, action) { 
    let id = Math.max.apply(this, Object.keys(state.files)) + 1; 
    return { 
    ...state, 
    fileOrder: addFileOrder(state.fileOrder, {id}), 
    files: handleAddFile(state.files, {id, name: action.name}) 
    }; 
} 

Obecnie jestem w stanie wysyłką pojedynczego działania {type: ADD_FILE, fileName: 'x'}, następnie addFile tworzy działań wewnętrznie wysłać do addFileOrder i addFile.

Jestem ciekawy, czy uważa się za lepsze podejście do jednej z poniższych.

Zamiast tego wywołaj dwie akcje, jedną, aby dodać plik, a następnie pobierz jego identyfikator i wywołaj akcję ADD_TO_FILE_ORDER z identyfikatorem. LUB Pożar i akcja, takie jak {type: ADD_FILE, name: 'x', id: 1}, zamiast zezwalać addFile na obliczanie nowego identyfikatora. To pozwoliłoby mi użyć combineReducers i filtrować na typ akcji. Ten przykład jest prawdopodobnie trywialny, ale moje rzeczywiste drzewo stanu jest nieco bardziej skomplikowane, z każdym dodawanym plikiem również wymagającym dodania do innych elementów.

Dla niektórych dodatkowych kontekstów wyglądałoby to bardziej kompletnie.

{ 
    "fileOrder": [0] 
    "entities": { 
     "files": { 
      0: { 
       id: 0, 
       name: 'hand.png' 
      } 
     }, 
     "animations": { 
      0: { 
       id: 0, 
       name: "Base", 
       frames: [0] 
      } 
     }, 
     "frames": { 
      0: { 
       id: 0, 
       duration: 500, 
       fileFrames: [0] 
      } 
     }, 
     "fileFrames": { 
      0: { 
       id: 0, 
       file: 0, 
       top: 0, 
       left: 0, 
       visible: true 
      }   
     } 
    } 
} 

Dodawanie pliku musiałaby:

  1. Dodaj go do mieszania plików.
  2. Dodaj do tablicy fileOrder.
  3. Dodaj fileFrame odwołujące się do pliku, dla każdej z ramek.
  4. Dodaj każdą nową ramkę fileFrame do ramki, dla której została utworzona.

Ostatnie dwa punkty sprawiają, że zastanawiam się, czy byłbym w stanie w ogóle użyć CombineReducers.

Odpowiedz

7

Skończyło się na znalezieniu całkiem prostego rozwiązania tego problemu.

Oba te bloki z dokumentacji są funkcjonalnie tym samym.

const reducer = combineReducers({ 
    a: doSomethingWithA, 
    b: processB, 
    c: c 
}); 

// This is functionally equivalent. 
function reducer(state, action) { 
    return { 
    a: doSomethingWithA(state.a, action), 
    b: processB(state.b, action), 
    c: c(state.c, action) 
    }; 
} 

Skończyłem podkręcać drugi blok i zawsze przechodząc wzdłuż mojego drzewa stanu globalnego. Dopóki nic nie zmienia stanu po drodze, wszystkie reduktory działają dobrze.

// Simple change to pass the entire state to each reducer. 
// You have to be extra careful to keep state immutable here. 
function reducer(state, action) { 
    return { 
    a: doSomethingWithA(state.a, action, state), 
    b: processB(state.b, action, state), 
    c: c(state.c, action, state) 
    }; 
} 
2

Opierając się na rozwiązanie autora:

miewam ten sam problem, gdy trzeba (tylko trochę) dostęp poza częścią mojego reduktora od państwa. Myślę, że to rozwiązanie może działać w praktyce, jeśli jesteś pilny, nie zmieniając niczego poza pojedynczą wartością, taką jak flaga lub licznik.

To nieczystość może szybko doprowadzić do szaleństwa, jeśli inni deweloperzy nie byliby tak zarezerwowani z ich kodem. Wyobraź sobie, co by się stało, gdyby zaczęła zmieniać część stanu b i c, zmieniając część a i c, i tak dalej.

Można rozważyć kurczy powierzchnię nieczystości tak:

function reducer(state, action) { 
    return { 
    a: doSomethingWithA(state.a, action, state.globals), 
    b: processB(state.b, action, state.globals), 
    c: c(state.c, action, state.globals) 
    }; 
} 
Powiązane problemy