React smart/dumb 用于更改数据的组件模式
react smart/dumb component pattern for changing data
我开始实施 smart/dumb 组件模式,其中 "dumb" 组件对其环境一无所知,并通过 props 接收所有数据。当哑组件必须提交或更改数据时,您会怎么做?怎么能和外界沟通,还"dumb"?
这是我用来弄清楚这个模式的基本示例。如果我要将 onClick
事件添加到 MyTask
更新数据库中的计数器的组件,将如何处理该事件?
// components/MyList.jsx
import React from 'react';
export default class MyList extends React.Component {
render() {
return(
<div>
<h3>{this.props.listName}</h3>
<ul>
{this.props.tasks.map((task) => (
<MyTask key={task.id} task={task} />
))}
</ul>
</div>
);
}
}
MyList.propTypes = {
listName: React.PropTypes.string.isRequired,
tasks: React.PropTypes.array.isRequired,
}
export class MyTask extends React.Component {
render() {
return (
<li>{this.props.task.text}</li>
);
}
}
MyTask.propTypes = {
task: React.PropTypes.object.isRequired,
}
和应用程序:
// app.jsx
import React from 'react';
import MyList from './components/MyList.jsx'
export class TaskApp extends React.Component {
getList() {
return('Today Stuff');
}
getTasks() {
return([
{id: 1, text: 'foo'},
{id: 2, text: 'diggity'},
{id: 3, text: 'boo'},
{id: 4, text: 'bop'}
]);
}
render() {
return (
<MyList listName={this.getList()} tasks={this.getTasks()} />
);
}
}
假设 TaskApp 是智能组件,MyList 是哑组件,它应该是这样的
智能组件
// app.jsx
import React from 'react';
import MyList from './components/MyList.jsx'
export class TaskApp extends React.Component {
getList() {
return('Today Stuff');
}
getTasks() {
return([
{id: 1, text: 'foo'},
{id: 2, text: 'diggity'},
{id: 3, text: 'boo'},
{id: 4, text: 'bop'}
]);
}
handleClick(task){
// update the db here
}
render() {
return (
<MyList listName={this.getList()} tasks={this.getTasks()}
onClick={this.handleClick}/>
);
}
}
哑组件
// components/MyList.jsx
import React from 'react';
export default class MyList extends React.Component {
render() {
return(
<div>
<h3>{this.props.listName}</h3>
<ul>
{this.props.tasks.map((task) => (
<MyTask onClick={() => this.props.onClick(task)}
key={task.id} task={task} />
))}
</ul>
</div>
);
}
}
MyList.propTypes = {
listName: React.PropTypes.string.isRequired,
tasks: React.PropTypes.array.isRequired,
}
export class MyTask extends React.Component {
render() {
return (
<li onClick={this.props.onClick}>{this.props.task.text}</li>
);
}
}
MyTask.propTypes = {
task: React.PropTypes.object.isRequired,
}
您可以将事件处理程序回调作为道具传递给 MyTask
:
<MyTask onClick={this.handleTaskClick.bind(this)} ... />
然后在MyTask中使用:
<li onClick={this.props.onClick}>...</li>
参见:https://facebook.github.io/react/docs/tutorial.html#callbacks-as-props
一般来说,您可以通过将函数引用从 'smart' 组件向下传递到 'dumb' 组件来处理此问题。哑组件不负责实现与该功能相关的任何逻辑,只是告诉智能组件“我被点击了”。
在这种情况下,在 app.jsx 中的 TaskApp class 中,您可以拥有点击处理程序:
//app.jsx
...
handleClick() {
// Update the DB counter by 1
}
...
render () {}
然后将 handleClick 作为道具传递给您的组件:
<MyList listName={this.getList()} tasks={this.getTasks()} handleClick={this.handleClick} />
<MyTask key={task.id} task={task} handleClick={this.props.handleClick} />
并在单击列表元素时在 MyTask 组件中执行它:
<li onClick={this.props.handleClick}>{this.props.task.text}</li>
请记住,如果 handleClick() 函数完全使用了 'this',则在向下传递(或绑定它)时,您需要在函数引用上添加 .bind(this)在构造函数中/使用 ES6 粗箭头函数)。
编辑:对于绑定'this'的其他方法的示例,您可以在class的构造函数中将绑定函数分配给您的this.handleClick参考,所以:
export default class TaskApp extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
...
...
}
这让您可以按照您通常期望的方式使用 this.handleClick。
或者您可以使用 ES6 粗箭头函数,它在调用时保留 'this' 的上下文:
<MyList
listName={this.getList()}
tasks={this.getTasks()}
handleClick={() => this.handleClick} />
我开始实施 smart/dumb 组件模式,其中 "dumb" 组件对其环境一无所知,并通过 props 接收所有数据。当哑组件必须提交或更改数据时,您会怎么做?怎么能和外界沟通,还"dumb"?
这是我用来弄清楚这个模式的基本示例。如果我要将 onClick
事件添加到 MyTask
更新数据库中的计数器的组件,将如何处理该事件?
// components/MyList.jsx
import React from 'react';
export default class MyList extends React.Component {
render() {
return(
<div>
<h3>{this.props.listName}</h3>
<ul>
{this.props.tasks.map((task) => (
<MyTask key={task.id} task={task} />
))}
</ul>
</div>
);
}
}
MyList.propTypes = {
listName: React.PropTypes.string.isRequired,
tasks: React.PropTypes.array.isRequired,
}
export class MyTask extends React.Component {
render() {
return (
<li>{this.props.task.text}</li>
);
}
}
MyTask.propTypes = {
task: React.PropTypes.object.isRequired,
}
和应用程序:
// app.jsx
import React from 'react';
import MyList from './components/MyList.jsx'
export class TaskApp extends React.Component {
getList() {
return('Today Stuff');
}
getTasks() {
return([
{id: 1, text: 'foo'},
{id: 2, text: 'diggity'},
{id: 3, text: 'boo'},
{id: 4, text: 'bop'}
]);
}
render() {
return (
<MyList listName={this.getList()} tasks={this.getTasks()} />
);
}
}
假设 TaskApp 是智能组件,MyList 是哑组件,它应该是这样的
智能组件
// app.jsx
import React from 'react';
import MyList from './components/MyList.jsx'
export class TaskApp extends React.Component {
getList() {
return('Today Stuff');
}
getTasks() {
return([
{id: 1, text: 'foo'},
{id: 2, text: 'diggity'},
{id: 3, text: 'boo'},
{id: 4, text: 'bop'}
]);
}
handleClick(task){
// update the db here
}
render() {
return (
<MyList listName={this.getList()} tasks={this.getTasks()}
onClick={this.handleClick}/>
);
}
}
哑组件
// components/MyList.jsx
import React from 'react';
export default class MyList extends React.Component {
render() {
return(
<div>
<h3>{this.props.listName}</h3>
<ul>
{this.props.tasks.map((task) => (
<MyTask onClick={() => this.props.onClick(task)}
key={task.id} task={task} />
))}
</ul>
</div>
);
}
}
MyList.propTypes = {
listName: React.PropTypes.string.isRequired,
tasks: React.PropTypes.array.isRequired,
}
export class MyTask extends React.Component {
render() {
return (
<li onClick={this.props.onClick}>{this.props.task.text}</li>
);
}
}
MyTask.propTypes = {
task: React.PropTypes.object.isRequired,
}
您可以将事件处理程序回调作为道具传递给 MyTask
:
<MyTask onClick={this.handleTaskClick.bind(this)} ... />
然后在MyTask中使用:
<li onClick={this.props.onClick}>...</li>
参见:https://facebook.github.io/react/docs/tutorial.html#callbacks-as-props
一般来说,您可以通过将函数引用从 'smart' 组件向下传递到 'dumb' 组件来处理此问题。哑组件不负责实现与该功能相关的任何逻辑,只是告诉智能组件“我被点击了”。
在这种情况下,在 app.jsx 中的 TaskApp class 中,您可以拥有点击处理程序:
//app.jsx
...
handleClick() {
// Update the DB counter by 1
}
...
render () {}
然后将 handleClick 作为道具传递给您的组件:
<MyList listName={this.getList()} tasks={this.getTasks()} handleClick={this.handleClick} />
<MyTask key={task.id} task={task} handleClick={this.props.handleClick} />
并在单击列表元素时在 MyTask 组件中执行它:
<li onClick={this.props.handleClick}>{this.props.task.text}</li>
请记住,如果 handleClick() 函数完全使用了 'this',则在向下传递(或绑定它)时,您需要在函数引用上添加 .bind(this)在构造函数中/使用 ES6 粗箭头函数)。
编辑:对于绑定'this'的其他方法的示例,您可以在class的构造函数中将绑定函数分配给您的this.handleClick参考,所以:
export default class TaskApp extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
...
...
}
这让您可以按照您通常期望的方式使用 this.handleClick。
或者您可以使用 ES6 粗箭头函数,它在调用时保留 'this' 的上下文:
<MyList
listName={this.getList()}
tasks={this.getTasks()}
handleClick={() => this.handleClick} />