【问题标题】:react smart/dumb component pattern for changing data响应智能/哑组件模式以更改数据
【发布时间】:2016-05-14 00:24:27
【问题描述】:

我开始实现智能/哑组件模式,其中“哑”组件对其环境一无所知,并通过道具接收所有数据。当哑组件必须提交或更改数据时,你会怎么做?怎么能和外界交流还“哑巴”呢?

这是我用来找出这种模式的基本示例。如果我要向更新数据库中的计数器的MyTask 组件添加和onClick 事件,该事件将如何处理?

// 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()} />
        );
    }
}

【问题讨论】:

    标签: meteor reactjs meteor-react


    【解决方案1】:

    一般来说,您可以通过将函数引用从“智能”组件传递到“哑”组件来处理此问题。然后,哑组件不负责实现与函数相关的任何逻辑,只是告诉智能组件“我已被点击”。

    在这种情况下,在 app.jsx 中的 TaskApp 类中,您可以使用点击处理程序:

    //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”的其他方法的示例,您可以在类的构造函数中将绑定函数分配给您的 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} />
    

    【讨论】:

    • 接受的答案在解释中有点冗长。谢谢!
    • 你能举例说明this 的两种不同绑定吗?这将是一个非常彻底的答案。
    • 在答案中添加了一些额外的绑定上下文示例。干杯!
    【解决方案2】:

    假设 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,
    }
    

    【讨论】:

      【解决方案3】:

      您可以将事件处理程序回调作为道具传递给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

      【讨论】:

      • 由于发布后几分钟内出现了三个非常相似的答案,这似乎是流行的方法。谢谢!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-07
      • 2017-08-29
      • 1970-01-01
      • 1970-01-01
      • 2013-11-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多