Fondamentalmente, oggetti di scena e stato sono due modi in cui il componente può sapere cosa e come renderizzare. Quale parte dello stato dell'applicazione appartiene allo stato e quale a un archivio di livello superiore, è più correlato al design dell'app, piuttosto che al modo in cui React funziona. Il modo più semplice per decidere, IMO, è di pensare se questo particolare dato è utile per l'applicazione nel suo insieme o se si tratta di alcune informazioni locali. Inoltre, è importante non duplicare lo stato, quindi se alcuni dati possono essere calcolati dai puntelli, dovrebbero essere calcolati dai puntelli.
Ad esempio, supponiamo che tu abbia un controllo a discesa (che avvolge la selezione HTML standard per lo stile personalizzato), che può a) selezionare un valore dall'elenco eb) essere aperto o chiuso (cioè l'elenco delle opzioni visualizzato o nascosto). Supponiamo ora che la tua app visualizzi un elenco di elementi di qualche tipo e che i controlli dei menu a discesa filtrino le voci dell'elenco. Quindi, sarebbe meglio passare il valore del filtro attivo come prop e mantenere lo stato aperto / chiuso locale. Inoltre, per renderlo funzionale, passeresti un gestore onChange dal componente genitore, che sarebbe chiamato all'interno dell'elemento a discesa e invierebbe immediatamente informazioni aggiornate (nuovo filtro selezionato) al negozio. D'altra parte, lo stato aperto / chiuso può essere mantenuto all'interno del componente a discesa, perché al resto dell'applicazione non importa davvero se il controllo è aperto, fino a quando l'utente non ne modifica il valore.
Il seguente codice non funziona completamente, ha bisogno di css e gestione degli eventi click / blur / change a discesa, ma volevo mantenere un esempio minimo. Spero che aiuti a capire la differenza.
const _store = {
items: [
{ id: 1, label: 'One' },
{ id: 2, label: 'Two' },
{ id: 3, label: 'Three', new: true },
{ id: 4, label: 'Four', new: true },
{ id: 5, label: 'Five', important: true },
{ id: 6, label: 'Six' },
{ id: 7, label: 'Seven', important: true },
],
activeFilter: 'important',
possibleFilters: [
{ key: 'all', label: 'All' },
{ key: 'new', label: 'New' },
{ key: 'important', label: 'Important' }
]
}
function getFilteredItems(items, filter) {
switch (filter) {
case 'all':
return items;
case 'new':
return items.filter(function(item) { return Boolean(item.new); });
case 'important':
return items.filter(function(item) { return Boolean(item.important); });
default:
return items;
}
}
const App = React.createClass({
render: function() {
return (
<div>
My list:
<ItemList items={this.props.listItems} />
<div>
<Dropdown
onFilterChange={function(e) {
_store.activeFilter = e.currentTarget.value;
console.log(_store); // in real life, some action would be dispatched here
}}
filterOptions={this.props.filterOptions}
value={this.props.activeFilter}
/>
</div>
</div>
);
}
});
const ItemList = React.createClass({
render: function() {
return (
<div>
{this.props.items.map(function(item) {
return <div key={item.id}>{item.id}: {item.label}</div>;
})}
</div>
);
}
});
const Dropdown = React.createClass({
getInitialState: function() {
return {
isOpen: false
};
},
render: function() {
return (
<div>
<select
className="hidden-select"
onChange={this.props.onFilterChange}
value={this.props.value}>
{this.props.filterOptions.map(function(option) {
return <option value={option.key} key={option.key}>{option.label}</option>
})}
</select>
<div className={'custom-select' + (this.state.isOpen ? ' open' : '')} onClick={this.onClick}>
<div className="selected-value">{this.props.activeFilter}</div>
{this.props.filterOptions.map(function(option) {
return <div data-value={option.key} key={option.key}>{option.label}</div>
})}
</div>
</div>
);
},
onClick: function(e) {
this.setState({
isOpen: !this.state.isOpen
});
}
});
ReactDOM.render(
<App
listItems={getFilteredItems(_store.items, _store.activeFilter)}
filterOptions={_store.possibleFilters}
activeFilter={_store.activeFilter}
/>,
document.getElementById('root')
);