Về cơ bản, đạo cụ và trạng thái là hai cách mà thành phần có thể biết những gì và làm thế nào để kết xuất. Phần nào của trạng thái ứng dụng thuộc về trạng thái và phần nào của một cửa hàng cấp cao nhất, có liên quan nhiều hơn đến thiết kế ứng dụng của bạn, hơn là cách React hoạt động. Cách đơn giản nhất để quyết định, IMO, là suy nghĩ, liệu phần dữ liệu cụ thể này có hữu ích cho toàn bộ ứng dụng hay đó là một số thông tin địa phương. Ngoài ra, điều quan trọng là không trùng lặp trạng thái, vì vậy nếu một số dữ liệu có thể được tính từ đạo cụ - thì nên tính toán từ đạo cụ.
Ví dụ: giả sử bạn có một số điều khiển thả xuống (bao gồm HTML standart chọn để tạo kiểu tùy chỉnh), có thể a) chọn một số giá trị từ danh sách và b) được mở hoặc đóng (nghĩa là danh sách tùy chọn được hiển thị hoặc ẩn). Bây giờ, giả sử ứng dụng của bạn hiển thị danh sách các mục thuộc loại nào đó và bộ lọc điều khiển thả xuống của bạn cho các mục nhập danh sách. Sau đó, tốt nhất là chuyển giá trị bộ lọc hoạt động dưới dạng prop và giữ trạng thái mở / đóng cục bộ. Ngoài ra, để làm cho nó hoạt động, bạn sẽ chuyển một trình xử lý onChange từ thành phần chính, được gọi là phần tử thả xuống bên trong và gửi thông tin cập nhật (bộ lọc được chọn mới) đến cửa hàng ngay lập tức. Mặt khác, trạng thái mở / đóng có thể được giữ trong thành phần thả xuống, bởi vì phần còn lại của ứng dụng không thực sự quan tâm nếu điều khiển được mở, cho đến khi người dùng thực sự thay đổi giá trị của nó.
Đoạn mã sau không hoàn toàn hoạt động, nó cần css và xử lý các sự kiện nhấp / làm mờ / thay đổi thả xuống, nhưng tôi muốn giữ ví dụ tối thiểu. Hy vọng nó sẽ giúp hiểu được sự khác biệt.
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')
);