2017-11-30 1 views
2

Der folgende Code erstellt eine einfache Filmrating App. Alles funktioniert, außer dass, wenn in einem der Array-Elemente auf eine Abstimmung nach oben oder unten geklickt wird, die Stimmen für alle Elemente in der Array-Aktualisierung angegeben werden und nicht nur für das Element, auf das geklickt wurde. Wie schreibe ich das so, dass die Abstimmung nur für den Gegenstand gilt, auf den geklickt wurde?Reagieren Anwendungsfunktion auf einzelnes Element in Array

class Ratings extends React.Component { 
    constructor(props){ 
     super(props); 
     this.state = { 
      votes: 0 
     }; 
     this.add = this.add.bind(this); 
     this.subtract = this.subtract.bind(this); 
     this.reset = this.reset.bind(this); 
    } 
    add(event){ 
     this.setState ({ 
      votes: this.state.votes + 1 
     }) 
    } 
    subtract(event){ 
     this.setState ({ 
      votes: this.state.votes - 1 
     }) 
    } 
    reset(event){ 
     this.setState ({ 
      votes: 0 
     }) 
    } 
    render() { 
     this.movies = this.props.list.map(x => { 
      return (
       <div key={x.id} className="movierater"> 
       <MoviePoster poster={x.img}/> 
       <h1 className="title">{x.name}</h1> 
        <div className="votewrapper"> 
         <button onClick={this.add}><i className="votebutton fa fa-thumbs-o-up" aria-hidden="true"></i></button> 
         <Votes count={this.state.votes} /> 
         <button onClick={this.subtract}><i className="votebutton fa fa-thumbs-o-down" aria-hidden="true"></i></button> 
        </div> 
       <button onClick={this.reset} className="reset">Reset</button> 
       </div> 
      ) 
     }); 
     return (
      <div> 
       {this.movies} 
      </div> 
     ); 
    } 
} 

function MoviePoster(props) { 
    return (
     <img src={props.poster} alt="Movie Poster" className="poster"/> 
    ); 
} 

function Votes(props) { 
    return (
     <h2>Votes: {props.count}</h2> 
    ); 
} 

var movieposters = [ 
    {id: 1, img:"http://www.impawards.com/2017/posters/med_alien_covenant_ver4.jpg", name: "Alien Covenant"}, 
    {id: 2, img:"http://www.impawards.com/2017/posters/med_atomic_blonde_ver4.jpg", name: "Atomic Blonde"}, 
    {id: 3, img:"http://www.impawards.com/2017/posters/med_easy_living_ver3.jpg", name: "Easy Living"}, 
    {id: 4, img:"http://www.impawards.com/2017/posters/med_once_upon_a_time_in_venice_ver3.jpg", name: "Once Upon a Time in Venice"}, 
    {id: 5, img:"http://www.impawards.com/2017/posters/med_scorched_earth.jpg", name: "Scorched Earth"}, 
    {id: 6, img:"http://www.impawards.com/2017/posters/med_underworld_blood_wars_ver9.jpg", name: "Underworld: Blood Wars"}, 
    {id: 7, img:"http://www.impawards.com/2017/posters/med_void.jpg", name: "The Void"}, 
    {id: 8, img:"http://www.impawards.com/2017/posters/med_war_for_the_planet_of_the_apes.jpg", name: "War for the Planet of the Apes"}, 
] 


ReactDOM.render(
    <Ratings list={movieposters} />, 
    document.getElementById('app') 
); 

Antwort

1

Sie benötigen eine separate Auszählung der Stimmen für jeden Film Einheit.
Dies kann erreicht werden, indem jedem Film eine ID zugewiesen wird und die Abstimmung für diesen bestimmten Film nach ID festgelegt wird.

Ich würde auch empfehlen, eine neue Komponente für eine Movie zu extrahieren.
Diese Komponente wird die movieId als Requisite und die Handler erhalten, wird es die Up- oder Down-Handler aufrufen und ihnen die aktuelle movieId bereitstellen.

Siehe Lauf Beispiel:

class Movie extends React.Component { 
 
    onSubtract =() => { 
 
    const { subtract, movieId } = this.props; 
 
    subtract(movieId); 
 
    }; 
 

 
    onAdd =() => { 
 
    const { add, movieId } = this.props; 
 
    add(movieId); 
 
    }; 
 

 
    onReset =() => { 
 
    const { reset, movieId } = this.props; 
 
    reset(movieId); 
 
    }; 
 

 
    render() { 
 
    const { movie, votes = 0 } = this.props; 
 
    return (
 
     <div className="movierater"> 
 
     <MoviePoster poster={movie.img} /> 
 
     <h1 className="title">{movie.name}</h1> 
 
     <div className="votewrapper"> 
 
      <button onClick={this.onAdd}> 
 
      <i className="votebutton fa fa-thumbs-o-up" aria-hidden="true" /> 
 
      </button> 
 
      <Votes count={votes} /> 
 
      <button onClick={this.onSubtract}> 
 
      <i className="votebutton fa fa-thumbs-o-down" aria-hidden="true" /> 
 
      </button> 
 
     </div> 
 
     <button onClick={this.onReset} className="reset"> 
 
      Reset 
 
     </button> 
 
     </div> 
 
    ); 
 
    } 
 
} 
 

 
class Ratings extends React.Component { 
 
    constructor(props) { 
 
    super(props); 
 
    this.state = { 
 
     allVotes: {} 
 
    }; 
 
    } 
 

 
    subtract = movieId => { 
 
    const { allVotes } = this.state; 
 
    const currentVote = allVotes[movieId] || 0; 
 
    const nextState = { 
 
     ...allVotes, 
 
     [movieId]: currentVote - 1 
 
    }; 
 
    this.setState({allVotes: nextState}); 
 
    }; 
 

 
    add = movieId => { 
 
    const { allVotes } = this.state; 
 
    const currentVote = allVotes[movieId] || 0; 
 
    const nextState = { 
 
     ...allVotes, 
 
     [movieId]: currentVote + 1 
 
    }; 
 
    this.setState({ allVotes: nextState }); 
 
    }; 
 

 
    reset = movieId => { 
 
    const { allVotes } = this.state; 
 
    const nextState = { 
 
     ...allVotes, 
 
     [movieId]: 0 
 
    }; 
 
    this.setState({ allVotes: nextState }); 
 
    }; 
 

 
    render() { 
 
    const { allVotes } = this.state; 
 
    this.movies = this.props.list.map(x => { 
 
     const votes = allVotes[x.id]; 
 
     return (
 
     <Movie 
 
      movieId={x.id} 
 
      movie={x} 
 
      votes={votes} 
 
      reset={this.reset} 
 
      subtract={this.subtract} 
 
      add={this.add} 
 
     /> 
 
    ); 
 
    }); 
 
    return <div>{this.movies}</div>; 
 
    } 
 
} 
 

 
function MoviePoster(props) { 
 
    return <img src={props.poster} alt="Movie Poster" className="poster" />; 
 
} 
 

 
function Votes(props) { 
 
    return <h2>Votes: {props.count}</h2>; 
 
} 
 

 
var movieposters = [ 
 
    { 
 
    id: 1, 
 
    img: "http://www.impawards.com/2017/posters/med_alien_covenant_ver4.jpg", 
 
    name: "Alien Covenant" 
 
    }, 
 
    { 
 
    id: 2, 
 
    img: "http://www.impawards.com/2017/posters/med_atomic_blonde_ver4.jpg", 
 
    name: "Atomic Blonde" 
 
    }, 
 
    { 
 
    id: 3, 
 
    img: "http://www.impawards.com/2017/posters/med_easy_living_ver3.jpg", 
 
    name: "Easy Living" 
 
    }, 
 
    { 
 
    id: 4, 
 
    img: 
 
     "http://www.impawards.com/2017/posters/med_once_upon_a_time_in_venice_ver3.jpg", 
 
    name: "Once Upon a Time in Venice" 
 
    }, 
 
    { 
 
    id: 5, 
 
    img: "http://www.impawards.com/2017/posters/med_scorched_earth.jpg", 
 
    name: "Scorched Earth" 
 
    }, 
 
    { 
 
    id: 6, 
 
    img: 
 
     "http://www.impawards.com/2017/posters/med_underworld_blood_wars_ver9.jpg", 
 
    name: "Underworld: Blood Wars" 
 
    }, 
 
    { 
 
    id: 7, 
 
    img: "http://www.impawards.com/2017/posters/med_void.jpg", 
 
    name: "The Void" 
 
    }, 
 
    { 
 
    id: 8, 
 
    img: 
 
     "http://www.impawards.com/2017/posters/med_war_for_the_planet_of_the_apes.jpg", 
 
    name: "War for the Planet of the Apes" 
 
    } 
 
]; 
 

 
ReactDOM.render(<Ratings list={movieposters} />, document.getElementById("root"));
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> 
 
<div id="root"></div>

+1

Thx, Sag1v. Ich dachte irgendwie, dass die Lösung komplizierter war, als ich dachte. Ich habe deinen Code implementiert und es hat funktioniert. Ich werde etwas Zeit investieren müssen, um es zu verstehen. Ich weiß wirklich zu schätzen, wie viel Mühe Sie darauf verwenden, meine Frage zu beantworten. –

+0

Ich bin froh, dass es für dich funktioniert hat –

1

Sie müssen für jedes Element Spur der Stimmen zu halten und so this.state.votes +/- 1 nicht den Job erledigen, so:

ändern

this.state = { 
    votes: 0 
} 

zu

this.state = { 
    votes: {} 
} 

dann ändern sich die Funktionen:

add(id){ 
    return function(event) { 
     this.setState ({ ...this.state.votes, [id]: parseInt(this.state.votes[id]) + 1 }) 
    } 
} 

und das gleiche für subtrahieren. Dann ändern Sie Ihre Tasten:

<button onClick={this.add(x.id)} ... (same for subtract) 

und letzte Änderung Ihrer Abstimmung Komponente:

<Votes count={this.state.votes[x.id] || 0} /> 

On-Reset nur tun:

reset(event){ 
    this.setState ({ votes: {} }) 
} 
+0

Hey Arber. Danke. Ich habe die von Ihnen vorgeschlagenen Änderungen vorgenommen, aber während das Array zum DOM ausgibt, geschieht nichts, wenn ich auf die Schaltflächen klicke. Müsste ich nicht auch die Votes-Funktion ändern? –

Verwandte Themen