Zasadniczo rekwizyty i stan to dwa sposoby, w jakie komponent może wiedzieć, co i jak renderować. Która część stanu aplikacji należy do stanu, a która do jakiegoś sklepu najwyższego poziomu, jest bardziej związana z projektem twojej aplikacji niż z działaniem React. Najprostszym sposobem na podjęcie decyzji, IMO, jest zastanowienie się, czy ten konkretny fragment danych jest przydatny do zastosowania jako całość, czy też jest to informacja lokalna. Ważne jest również, aby nie powielać stanu, więc jeśli jakiś kawałek danych można obliczyć na podstawie rekwizytów - powinien on zostać obliczony na podstawie rekwizytów.
Na przykład, powiedzmy, że masz kontrolę rozwijaną (która otacza standardowy HTML wybierz do niestandardowego stylu), która może a) wybrać pewną wartość z listy, i b) otworzyć lub zamknąć (tj. Wyświetlić lub ukryć listę opcji). Załóżmy teraz, że twoja aplikacja wyświetla listę elementów, a lista kontrolna listy kontrolnej filtruje wpisy listy. Wtedy najlepiej byłoby przekazać wartość aktywnego filtra jako rekwizyt i zachować lokalny stan otwarty / zamknięty. Ponadto, aby działał, należy przekazać moduł obsługi onChange z komponentu nadrzędnego, który zostanie nazwany wewnątrz elementu rozwijanego i natychmiast wyśle zaktualizowane informacje (nowy wybrany filtr) do sklepu. Z drugiej strony, stan otwarty / zamknięty może być utrzymany w rozwijanym składniku, ponieważ reszta aplikacji tak naprawdę nie dba o to, czy kontrola jest otwarta, dopóki użytkownik nie zmieni jej wartości.
Poniższy kod nie działa całkowicie, wymaga css i obsługi rozwijanych zdarzeń kliknięcia / rozmycia / zmiany, ale chciałem zachować przykład na minimalnym poziomie. Mam nadzieję, że pomaga zrozumieć różnicę.
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')
);