2015-09-26 13 views
18

Sono un po 'bloccato pensando a come implementare un riduttore in cui le sue entità possono avere figli dello stesso tipo.Come gestire le entità a forma di albero nei riduttori Redux?

Prendiamo commenti reddit come un esempio: ogni commento può commenti bambino han che può avere i commenti stessi ecc Per motivi di semplificazione, un commento è un record di tipo {id, pageId, il valore, i bambini}, con l'essere pageId la pagina di reddit.

Come si modellerebbe il riduttore intorno a questo? Stavo pensando di fare in modo che il riduttore sia una mappa -> id dei commenti dove è possibile filtrare per pagina usando l'ID pagina.

Il problema è che ad esempio quando vogliamo aggiungere un commento ad uno nidificato: dobbiamo creare il record sulla radice della mappa e quindi aggiungere il suo id nella proprietà parent children. Per visualizzare tutti i commenti avremmo bisogno di ottenerli tutti, filtrare quelli che abbiamo in cima (che verrebbero mantenuti nei riduttori di pagine come una lista ordinata per esempio) e poi scorrere su di essi, recuperando dagli oggetti dei commenti quando incontriamo dei bambini che usano ricorsione.

C'è un approccio migliore di quello o è difettoso?

+0

Penso che potresti provare normalizr: https://github.com/gaearon/normalizr Non l'ho usato da solo, quindi non sono sicuro che ti aiuterà nel tuo caso. – Simon

+0

So di normalizzazione, mi chiedo di più se esiste una soluzione "accettata" su come gestirla nei componenti. A meno che non si connetta() ogni commento sarà necessario fare l'opposto di normalizr su ogni cambiamento e anche se lo si connette sembra un po 'un casino –

risposta

32

La soluzione ufficiale a questo è quello di utilizzare normalizr per mantenere il tuo stato in questo modo:

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

Hai ragione che avresti bisogno di connect() componente Comment modo ciascuno può ricorsivamente interrogare la children è interessata in dal negozio 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; 

Pensiamo che questo sia un buon compromesso. Si passa comment come sostegno, ma il componente recupera childrenComments dal negozio.

+0

Come si fa a farlo con Schemas? Si prega di fornire un esempio – alexrogins

+0

Questo esempio utilizza normalizr: https://github.com/reactjs/redux/tree/master/examples/real-world. Anche normalizr ha test che dovrebbero mostrare come usarlo. –

+0

Cosa succede se i tuoi dati non provengono da un'API? Dovrei semplicemente modellare i miei dati come fa normalizr? – Dave

1

La struttura del tuo negozio (riduttore) potrebbe differire dal modello di visualizzazione desiderato (uno che passi come oggetti di scena ai componenti). Puoi semplicemente mantenere tutti i commenti in array e mapparli a un albero tramite collegamenti in mapStateToProps sul componente 'smart' di alto livello. Otterrai una gestione dello stato semplice in riduttore e un pratico modello di visualizzazione per i componenti con cui lavorare.