2015-09-26 15 views
18

Trochę utknąłem, myśląc o tym, jak zaimplementować reduktor, w którym jego jednostki mogą mieć dzieci tego samego typu.Jak obsługiwać obiekty w kształcie drzewa w reduktorach Redux?

Weźmy przykładowe uwagi reddit: każdy komentarz może zawierać komentarze potomne, które mogą same mieć komentarze. Dla uproszczenia komentarz jest rekordem typu {id, pageId, value, children}, z pageId being strona reddit.

Jak można modelować reduktor wokół tego? Myślałem o tym, że reduktor jest mapą -> id komentarzy, które można filtrować według stron za pomocą strony id.

Problem polega na tym, że na przykład, gdy chcemy dodać komentarz do zagnieżdżonego: musimy utworzyć rekord w katalogu głównym mapy, a następnie dodać jego identyfikator do właściwości rodzica podrzędnego.Aby wyświetlić wszystkie komentarze musielibyśmy uzyskać wszystkie z nich, odfiltrować te, które mamy na górze (które zostałyby zachowane w reduktorach strony, jak na przykład uporządkowaną listę), a następnie iterować je, pobierając z obiektów komentarzy, gdy napotykamy dzieci używające rekurencja.

Czy istnieje lepsze podejście niż to, czy jest wadliwe?

+0

Myślę, że możesz spróbować normalizr: https://github.com/gaearon/normalizr Nie użyłem go sam, więc nie jestem pewien, czy to ci pomoże w twoim przypadku. – Simon

+0

Wiem o normalizatorze, bardziej zastanawiam się, czy istnieje "akceptowane" rozwiązanie, jak sobie z nim radzić w komponentach. Jeśli nie podłączysz() każdego komentarza, będziesz musiał zrobić odwrotność normalizatora przy każdej zmianie, a nawet jeśli połączysz to wygląda trochę jak bałagan –

Odpowiedz

32

Oficjalna Rozwiązaniem tego problemu jest użycie normalizr aby utrzymać swój stan tak:

{ 
    comments: { 
    1: { 
     id: 1, 
     children: [2, 3] 
    }, 
    2: { 
     id: 2, 
     children: [] 
    }, 
    3: { 
     id: 3, 
     children: [42] 
    }, 
    ... 
    } 
} 

Masz rację, że trzeba by connect() komponentu Comment więc każdy może rekurencyjnie kwerendy children To zainteresowany ze sklepu Redux:

class Comment extends Component { 
    static propTypes = { 
    comment: PropTypes.object.isRequired, 
    childComments: PropTypes.arrayOf(PropTypes.object.isRequired).isRequired 
    }, 

    render() { 
    return (
     <div> 
     {this.props.comment.text} 
     {this.props.childComments.map(child => <Comment key={child.id} comment={child} />)} 
     </div> 
    ); 
    } 
} 

function mapStateToProps(state, ownProps) { 
    return { 
    childComments: ownProps.comment.children.map(id => state.comments[id]) 
    }; 
} 

Comment = connect(mapStateToProps)(Comment); 
export default Comment; 

Uważamy, że jest to dobry kompromis. Przekazujesz comment jako rekwizyt, ale komponent pobiera childrenComments ze sklepu.

+0

Jak to się dzieje w Schemasach? Proszę podać przykład: – alexrogins

+0

Ten przykład używa normalizr: https://github.com/reactjs/redux/tree/master/examples/real-world. Również normalizr ma testy, które miejmy nadzieję powinny pokazać, jak z niego korzystać. –

+0

Co jeśli twoje dane nie pochodzą z interfejsu API? Czy powinienem po prostu modelować moje dane tak, jak robi to normalizr? – Dave

1

Twoja struktura sklepu (reduktora) może różnić się od pożądanego modelu widoku (jeden przekazujesz jako rekwizyty do komponentów). Możesz przechowywać wszystkie komentarze w tablicy i mapować je do drzewa za pomocą linków w mapStateToProps na "inteligentnym" komponencie wysokiego poziomu. Otrzymasz proste zarządzanie stanem w reduktorze i poręczny model widoku dla komponentów do pracy.