【问题标题】:Expected onClick listener to be a function, instead got type object - react redux期望 onClick 侦听器是一个函数,而不是类型对象-react redux
【发布时间】:2017-12-03 15:41:21
【问题描述】:

如标题中所述,我收到了错误消息 期望 onClick 监听器是一个函数,而不是类型对象

但我无法理解为什么这不起作用。 据我所知,onClick 监听器是一个函数。

这是错误来自的 CharacterList 组件

import React,{Component} from 'react';
import {connect} from 'react-redux';
import {addCharacterById} from '../actions';
import {bindActionCreators} from 'redux';


class CharacterList extends Component{

    render(){
        //console.log('name : ',this.props.characters[2].name);
        return(
            <div>
            <h3>Characters</h3>
        <ul>
        {this.props.characters.map((character)=>{
            return(<li key={character.id}>{character.name}
                <div
                onClick={this.props.addCharacterById(character.id)}
                >+</div>
                </li>);
        })}
        </ul>
            </div>

            )
    }
}

function mapStateToProps(state){
    return {
        characters:state
    }
}




export default connect(mapStateToProps,{addCharacterById})(CharacterList);

这里是动作创建者

export const ADD_CHARACTER='ADD_CHARACTER';
export function addCharacterById(id){
    var action ={
        type:ADD_CHARACTER,
            id
        }
        return action;

}

那么,你们觉得呢? 这里有什么问题?

【问题讨论】:

  • "据我所知,onClick 监听器是一个函数。"您确定吗? console.log 是一个函数。 console.log("Hello") 是函数吗?
  • 你在哪里看到console.log("hello")??
  • 这是一个类比。 this.props.addCharacterById 是一个函数。 this.props.addCharacterById(character.id) 是函数吗?
  • 函数调用不是函数。函数调用返回一个值。您没有将函数作为 onClick 属性传递。您正在传递函数返回的值。
  • 嗯,是的。也阅读其他答案,说同样的话。我想我现在明白了。

标签: javascript reactjs redux react-redux


【解决方案1】:

不要在onClick 事件中直接调用函数。它将递归调用该方法。所以将onClick 输入作为回调方法。

改变这一行

onClick={this.props.addCharacterById(character.id)}

onClick={() => this.props.addCharacterById(character.id)}

【讨论】:

    【解决方案2】:

    问题是你立即调用函数,然后剩下的是返回值,它可能不是一个函数!

    您可以做的是将该函数调用包装在箭头函数中以解决您的问题。一旦你点击它就会调用内部函数:

    import React,{Component} from 'react';
    import {connect} from 'react-redux';
    import {addCharacterById} from '../actions';
    import {bindActionCreators} from 'redux';
    
    
    class CharacterList extends Component{
    
        render(){
            //console.log('name : ',this.props.characters[2].name);
            return(
                <div>
                <h3>Characters</h3>
            <ul>
            {this.props.characters.map((character)=>{
                return(<li key={character.id}>{character.name}
                    <div
                    onClick={() => this.props.addCharacterById(character.id)}
                    >+</div>
                    </li>);
            })}
            </ul>
                </div>
    
                )
        }
    }
    
    function mapStateToProps(state){
        return {
            characters:state
        }
    }
    
    
    
    
    export default connect(mapStateToProps,{addCharacterById})(CharacterList);
    

    有不同的方法可以做到这一点,例如,您可以将参数绑定到函数,例如:

    {this.props.characters.map((character)=>{
        return(<li key={character.id}>{character.name}
            <div
            onClick={this.props.addCharacterById.bind(null, character.id)}
            >+</div>
            </li>);
    })}
    

    仅作为示例分享,以便您了解发生了什么以及为什么第一种方法更具可读性。您可能想通过阅读文章https://ryanfunduk.com/articles/never-bind-in-render/

    来了解为什么渲染中的 .bind 是一种不好的做法

    【讨论】:

    • 内联函数不是对性能不利吗?你使用内联函数:onClick={() =&gt; this.props.addCharacterById(character.id)}。 Funct 和 obj 是引用类型,因此每次重新渲染应用程序时,render() 方法中的每个 func 都将在内存中的不同位置重新创建。如果这是真的,请告诉我你为什么用 inline func 展示这个例子?
    • 嗨@dragon,我在 SO 中的所有答案都保持简单、清晰和有用。性能和优化是一个不同的话题,不要以为用户提出问题的时候就理解了这个问题,所以我们也要尊重这一点。一旦 OP 了解了为什么/如何,阅读十亿篇文章中的一篇就很简单了,包括扩展它的原始 React 文档。这是一篇关于它的好文章(flexport.engineering/…)。
    【解决方案3】:

    如果你想拥有良好的实践,你需要改变一些事情。

    首先,添加mapDispatchToProps函数。

    import { bindActionCreators } from 'redux';
    ...
    function mapDispatchToProps(dispatch) {
      return {
        addCharacterById: bindActionCreators(addCharacterById, dispatch)
      };
    }
    

    其次,事件处理程序可以是:

    onClick={() => this.props.addCharacterById(character.id)}
    

    第三,导出你的组件:

    export default connect(mapStateToProps, mapDispatchToProps)(CharacterList);
    

    【讨论】:

    • 你能解释一下为什么你使用 bindActionCreators 的方式,而不是下面这样: function mapDispatchToProps(dispatch){ bindActionCreators({addCharacterById},dispatch); } 哪个更好?
    • @faraz 我把 bindActionCreators 函数放在我的答案中,因为你的例子中有它,但实际上没有必要。 bindActionCreators 的唯一用例是当您想将一些操作创建者传递给不了解 Redux 的组件,并且您不想将调度或 Redux 存储传递给它时。
    【解决方案4】:

    onClick={this.props.addCharacterById(character.id)} 这部分代码将在调用render() 时立即执行,您可能想做的是:

    onClick={(e)=&gt; {this.props.addCharacterById(e, character.id)}}

    记住传递给onClick 的第一个参数是点击事件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-26
      • 1970-01-01
      • 2019-05-29
      • 1970-01-01
      • 1970-01-01
      • 2018-10-18
      • 2022-08-07
      相关资源
      最近更新 更多