Fondamentalement, les accessoires et l'état sont deux façons dont le composant peut savoir quoi et comment rendre. Quelle partie de l'état de l'application appartient à l'état et laquelle, dans un magasin de niveau supérieur, est plus liée à la conception de votre application qu'à la façon dont React fonctionne. L'OMI, la manière la plus simple de décider, est de se demander si cette donnée particulière est utile pour l'application dans son ensemble ou s'il s'agit d'informations locales. En outre, il est important de ne pas dupliquer l'état, donc si certaines données peuvent être calculées à partir d'accessoires - elles doivent être calculées à partir d'accessoires.
Par exemple, supposons que vous ayez un contrôle déroulant (qui englobe la sélection HTML standard pour un style personnalisé), qui peut a) sélectionner une valeur dans la liste, et b) être ouvert ou fermé (c'est-à-dire la liste d'options affichée ou masquée). Supposons maintenant que votre application affiche une liste d'éléments en quelque sorte et que votre contrôle déroulant filtre les entrées de liste. Ensuite, il serait préférable de passer la valeur du filtre actif comme accessoire et de maintenir l'état ouvert / fermé local. De plus, pour le rendre fonctionnel, vous passeriez un gestionnaire onChange du composant parent, qui serait appelé à l'intérieur de l'élément de liste déroulante et enverrait immédiatement les informations mises à jour (nouveau filtre sélectionné) au magasin. D'un autre côté, l'état ouvert / fermé peut être conservé à l'intérieur du composant déroulant, car le reste de l'application ne se soucie pas vraiment si le contrôle est ouvert, jusqu'à ce que l'utilisateur modifie réellement sa valeur.
Le code suivant ne fonctionne pas complètement, il a besoin de CSS et de gérer les événements de clic / flou / changement de liste déroulante, mais je voulais garder un exemple minimal. J'espère que cela aide à comprendre la différence.
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')
);