it-roy-ru.com

Предполагается, что прослушиватель onClick будет функцией, вместо этого получен объект типа - реагировать на избыточность

Как объясняется в заголовке, я получаю сообщение об ошибке Ожидаемый прослушиватель onClick будет функцией, вместо этого получен объект типа

Но я не могу понять, почему это не работает. насколько я знаю, слушатель onClick IS функция.

Вот компонент 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;

}

Так что вы думаете, ребята? в чем здесь проблема?

6
faraz

Проблема в том, что вы вызываете функцию немедленно, а затем остается возвращаемое значение, которое может не быть функцией! 

Вместо этого вы можете заключить вызов этой функции в функцию стрелки, чтобы решить вашу проблему. Он вызовет внутреннюю функцию, как только вы нажмете на:

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

Просто поделился в качестве примера, чтобы вы поняли, что происходит и почему первый подход более читабелен. Возможно, вы захотите узнать, почему .bind в рендере является плохой практикой, прочитав статью https://ryanfunduk.com/articles/never-bind-in-render/

15
punkbit

onClick={this.props.addCharacterById(character.id)} эта часть вашего кода будет выполняться сразу после вызова render(), что вы, возможно, захотите сделать:

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

Помните, что первая передача параметра в onClick - это событие click. 

4
yahiramat

Есть некоторые вещи, которые вам нужно изменить, если вы хотите иметь хорошие практики.

Сначала добавьте функцию 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);
2
slorenzo