使用 React 一次突出显示一个对象
Highlighting one object at a time with React
我对 React 和 Javascript 都很陌生,我已经通过构建一个简单的可折叠菜单开始学习它。它按预期工作,除了我不知道如何一次只突出显示一个项目。我怀疑 onClick 方法和状态必须由比 sectionItem 更高级别 class 拥有,但我真的很困惑如何使它起作用。然后,我的第一直觉是每次单击某项时都遍历菜单中的所有项目,并确保所有其他项目都切换为 active=false。
这是正确的思考方式吗?有人可以解释一下在这种情况下状态在 React 中是如何工作的,以及我应该如何在这里实现它?
完整代码可在此处获得:Menu on codepen.io
这是我要突出显示的项目的代码。我还不能实现一次只突出显示一项。
var SectionItem = React.createClass({
handleClick: function(){
if(!this.state.active) {
this.setState({
currentItem: this,
active: true,
class: "sectionitem active"});
}
},
getInitialState: function(){
return {
active: false,
class: "sectionitem"
}
},
render: function() {
return (
<div className={this.state.class} onClick={this.handleClick}>{this.props.title}</div>
);
}
});
伟大的开始!让我们先解决一下代码中的一些问题。
关注点分离
无需在 top-most 组件中创建整个嵌套结构。这很做作:
for (i=0; i < this.props.menuitems.length; i++) {
if(this.props.menuitems[i].section !== lastSection) {
var section = this.props.menuitems[i].section;
var items = [];
for (j=0; j < this.props.menuitems.length; j++) {
if(this.props.menuitems[j].section == section) {
var itemName = this.props.menuitems[j].name;
items.push(<SectionItem title={itemName} key={itemName} />);
};
}
sections.push(<Section title={section} items={items} key={section} />);
lastSection = section;
}
}
恰恰相反。您应该尝试让每个组件负责呈现自己的信息。如果我们首先处理您的数据,我们可以改进这一点。问题是您的部分没有嵌套。如果不是这个...
var MENU_ITEMS = [
{section: "About", name: "Hey", key: "Hey", selected: true},
{section: "About", name: "No", key: "No", selected: false},
{section: "About", name: "Way", key: "Way", selected: false},
{section: "People", name: "Cakewalk", key: "Cakewalk", selected: false},
{section: "People", name: "George", key: "George", selected: false},
{section: "People", name: "Adam", key: "Adam", selected: false},
{section: "Projects", name: "Pirate raid", key: "Pirate raid", selected: false},
{section: "Projects", name: "Goosehunt", key: "Goosehunt", selected: false},
];
我们有这个:
var sections = [
{
name: "About",
items: [
{name: "Hey", key: "Hey", selected: true},
{name: "No", key: "No", selected: false},
{name: "Way", key: "Way", selected: false}
]
},{
name: "People",
items: [
{name: "Cakewalk", key: "Cakewalk", selected: false},
{name: "George", key: "George", selected: false},
{name: "Adam", key: "Adam", selected: false}
]
},{
name: "Projects",
items: [
{name: "Pirate raid", key: "Pirate raid", selected: false},
{name: "Goosehunt", key: "Goosehunt", selected: false}
]
}
];
然后我们可以简化Accordion
很多。我们简单地为每个 section
:
渲染一个 Section
var Accordion = React.createClass({
render: function() {
return (
<div className="main">
{this.props.sections.map(function(section){
return <Section key={section.name} section={section}/>
})}
</div>
);
}
});
同样,Section 和 SectionItem 变得非常简单。
var Section = React.createClass({
handleClick: function(){
this.setState({
open: !this.state.open,
class: this.state.open ? "section" : "section open"
});
},
getInitialState: function(){
return {
open: false,
class: "section"
}
},
render: function() {
return (
<div className={this.state.class}>
<div className="sectionhead" onClick={this.handleClick}>{this.props.section.name}</div>
<div className="articlewrap">
<div className="article">
{this.props.section.items.map(function(item){
return <SectionItem key={item.name} item={item}/>
})}
</div>
</div>
</div>
);
}
});
var SectionItem = React.createClass({
handleClick: function(){
this.setState({
currentItem: this,
active: !this.state.active,
class: this.state.active ? "sectionitem" : "sectionitem active"
});
},
getInitialState: function(){
return {
active: false,
class: "sectionitem"
}
},
render: function() {
return (
<div className={this.state.class} onClick={this.handleClick}>{this.props.item.name}</div>
);
}
});
传播状态改变
现在,回到你原来的问题。在更复杂的应用程序中,您可以从更强大的东西中受益,例如 Flux. However, for now, following the techniques exposed in Thinking in React 应该可以解决您的问题。
确实,一种好方法是将 "what is open" 的状态带到 Accordion
组件中。您只需要让您的 parent 知道有东西被点击了。我们可以通过作为 prop
.
传递的回调来做到这一点
因此,Accordion
可以有一个 openSection
状态,以及一个 onChildClick
接收被点击部分的名称。它需要将 onChildClick
传递给每个 Section
.
var Accordion = React.createClass({
getInitialState: function() {
return {
openSection: null
};
},
onChildClick: function(sectionName) {
this.setState({
openSection: sectionName
});
},
render: function() {
return (
<div className="main">
{this.props.sections.map(function(section){
return <Section key={section.name}
onChildClick={this.onChildClick}
open={this.state.openSection===section.name}
section={section}/>
}.bind(this))}
</div>
);
}
});
而 Section
只需在单击时调用此函数,并传入它自己的名称。
var Section = React.createClass({
handleClick: function(){
this.props.onChildClick(this.props.section.name);
},
render: function() {
var className = this.props.open ? "section open" : "section"
return (
<div className={className}>
<div className="sectionhead" onClick={this.handleClick}>{this.props.section.name}</div>
<div className="articlewrap">
<div className="article">
{this.props.section.items.map(function(item){
return <SectionItem key={item.name} item={item}/>
})}
</div>
</div>
</div>
);
}
});
您可以将此解决方案外推到 SectionItem
问题。
生成的代码笔在这里:http://codepen.io/gadr90/pen/wamQXG?editors=001
祝你学习 React 顺利!你走在正确的道路上。
我对 React 和 Javascript 都很陌生,我已经通过构建一个简单的可折叠菜单开始学习它。它按预期工作,除了我不知道如何一次只突出显示一个项目。我怀疑 onClick 方法和状态必须由比 sectionItem 更高级别 class 拥有,但我真的很困惑如何使它起作用。然后,我的第一直觉是每次单击某项时都遍历菜单中的所有项目,并确保所有其他项目都切换为 active=false。
这是正确的思考方式吗?有人可以解释一下在这种情况下状态在 React 中是如何工作的,以及我应该如何在这里实现它?
完整代码可在此处获得:Menu on codepen.io
这是我要突出显示的项目的代码。我还不能实现一次只突出显示一项。
var SectionItem = React.createClass({
handleClick: function(){
if(!this.state.active) {
this.setState({
currentItem: this,
active: true,
class: "sectionitem active"});
}
},
getInitialState: function(){
return {
active: false,
class: "sectionitem"
}
},
render: function() {
return (
<div className={this.state.class} onClick={this.handleClick}>{this.props.title}</div>
);
}
});
伟大的开始!让我们先解决一下代码中的一些问题。
关注点分离
无需在 top-most 组件中创建整个嵌套结构。这很做作:
for (i=0; i < this.props.menuitems.length; i++) {
if(this.props.menuitems[i].section !== lastSection) {
var section = this.props.menuitems[i].section;
var items = [];
for (j=0; j < this.props.menuitems.length; j++) {
if(this.props.menuitems[j].section == section) {
var itemName = this.props.menuitems[j].name;
items.push(<SectionItem title={itemName} key={itemName} />);
};
}
sections.push(<Section title={section} items={items} key={section} />);
lastSection = section;
}
}
恰恰相反。您应该尝试让每个组件负责呈现自己的信息。如果我们首先处理您的数据,我们可以改进这一点。问题是您的部分没有嵌套。如果不是这个...
var MENU_ITEMS = [
{section: "About", name: "Hey", key: "Hey", selected: true},
{section: "About", name: "No", key: "No", selected: false},
{section: "About", name: "Way", key: "Way", selected: false},
{section: "People", name: "Cakewalk", key: "Cakewalk", selected: false},
{section: "People", name: "George", key: "George", selected: false},
{section: "People", name: "Adam", key: "Adam", selected: false},
{section: "Projects", name: "Pirate raid", key: "Pirate raid", selected: false},
{section: "Projects", name: "Goosehunt", key: "Goosehunt", selected: false},
];
我们有这个:
var sections = [
{
name: "About",
items: [
{name: "Hey", key: "Hey", selected: true},
{name: "No", key: "No", selected: false},
{name: "Way", key: "Way", selected: false}
]
},{
name: "People",
items: [
{name: "Cakewalk", key: "Cakewalk", selected: false},
{name: "George", key: "George", selected: false},
{name: "Adam", key: "Adam", selected: false}
]
},{
name: "Projects",
items: [
{name: "Pirate raid", key: "Pirate raid", selected: false},
{name: "Goosehunt", key: "Goosehunt", selected: false}
]
}
];
然后我们可以简化Accordion
很多。我们简单地为每个 section
:
Section
var Accordion = React.createClass({
render: function() {
return (
<div className="main">
{this.props.sections.map(function(section){
return <Section key={section.name} section={section}/>
})}
</div>
);
}
});
同样,Section 和 SectionItem 变得非常简单。
var Section = React.createClass({
handleClick: function(){
this.setState({
open: !this.state.open,
class: this.state.open ? "section" : "section open"
});
},
getInitialState: function(){
return {
open: false,
class: "section"
}
},
render: function() {
return (
<div className={this.state.class}>
<div className="sectionhead" onClick={this.handleClick}>{this.props.section.name}</div>
<div className="articlewrap">
<div className="article">
{this.props.section.items.map(function(item){
return <SectionItem key={item.name} item={item}/>
})}
</div>
</div>
</div>
);
}
});
var SectionItem = React.createClass({
handleClick: function(){
this.setState({
currentItem: this,
active: !this.state.active,
class: this.state.active ? "sectionitem" : "sectionitem active"
});
},
getInitialState: function(){
return {
active: false,
class: "sectionitem"
}
},
render: function() {
return (
<div className={this.state.class} onClick={this.handleClick}>{this.props.item.name}</div>
);
}
});
传播状态改变
现在,回到你原来的问题。在更复杂的应用程序中,您可以从更强大的东西中受益,例如 Flux. However, for now, following the techniques exposed in Thinking in React 应该可以解决您的问题。
确实,一种好方法是将 "what is open" 的状态带到 Accordion
组件中。您只需要让您的 parent 知道有东西被点击了。我们可以通过作为 prop
.
因此,Accordion
可以有一个 openSection
状态,以及一个 onChildClick
接收被点击部分的名称。它需要将 onChildClick
传递给每个 Section
.
var Accordion = React.createClass({
getInitialState: function() {
return {
openSection: null
};
},
onChildClick: function(sectionName) {
this.setState({
openSection: sectionName
});
},
render: function() {
return (
<div className="main">
{this.props.sections.map(function(section){
return <Section key={section.name}
onChildClick={this.onChildClick}
open={this.state.openSection===section.name}
section={section}/>
}.bind(this))}
</div>
);
}
});
而 Section
只需在单击时调用此函数,并传入它自己的名称。
var Section = React.createClass({
handleClick: function(){
this.props.onChildClick(this.props.section.name);
},
render: function() {
var className = this.props.open ? "section open" : "section"
return (
<div className={className}>
<div className="sectionhead" onClick={this.handleClick}>{this.props.section.name}</div>
<div className="articlewrap">
<div className="article">
{this.props.section.items.map(function(item){
return <SectionItem key={item.name} item={item}/>
})}
</div>
</div>
</div>
);
}
});
您可以将此解决方案外推到 SectionItem
问题。
生成的代码笔在这里:http://codepen.io/gadr90/pen/wamQXG?editors=001
祝你学习 React 顺利!你走在正确的道路上。