web-dev-qa-db-fra.com

L’écouteur onClick attendu est une fonction, mais un objet de type obtenu - réagit à redux

Comme expliqué dans le titre, l'erreur se produit L'auditeur onClick attendu est une fonction, mais un objet de type 

Mais je suis incapable de comprendre pourquoi cela ne marche pas ... autant que je sache, l'écouteur onClick IS est une fonction.

Voici le composant CharacterList d'où provient l'erreur

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

Et voici le créateur d'action

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

}

Alors, qu'en pensez-vous? Quel est le problème ici?

6
faraz

Le problème est que vous appelez la fonction immédiatement et qu'il ne reste que la valeur de retour, qui peut ne pas être une fonction! 

Au lieu de cela, vous pouvez insérer cet appel de fonction dans une fonction de flèche pour résoudre votre problème. Il appellera la fonction interne une fois que vous aurez cliqué:

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

Il y a différentes façons de le faire, vous pouvez par exemple lier le paramètre à la fonction, par exemple:

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

Juste partagé à titre d'exemple, pour que vous compreniez ce qui se passe et pourquoi la première approche est plus lisible. Vous voudrez peut-être comprendre pourquoi .bind dans le rendu est une mauvaise pratique en lisant l'article https://ryanfunduk.com/articles/never-bind-in-render/

15
punkbit

Il y a des choses que vous devez changer si vous voulez avoir de bonnes pratiques.

Premièrement, ajoutez la fonction mapDispatchToProps.

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

Deuxièmement, le gestionnaire d'événement pourrait être:

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

Troisièmement, exportez votre composant:

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