Pour une raison quelconque, onClick ne se déclenchera pas une fois, mais s'il est cliqué deux fois. L'action this.props.PostLike (id) sera déclenchée, que dois-je faire pour que cela fonctionne en un seul clic.
De plus, l'état du cœur fonctionne bien, en un seul clic. Il suffit de cliquer deux fois sur this.props.postLike pour que cela fonctionne.
Et utiliser e.preventDefault () ne résout pas le problème.
import React, { Component } from 'react';
import Paper from '@material-ui/core/Paper';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import moment from 'moment';
import {connect} from 'react-redux';
import { withRouter, Redirect} from 'react-router-dom';
import {DeletePost, postLike, UpdatePost,EditChange, GetPosts, getCount, DisableButton} from '../actions/';
import PostItem from './PostItem';
import _ from 'lodash';
const Styles = {
myPaper: {
margin: '20px 0px',
padding: '20px'
}
}
class PostList extends Component{
constructor(props){
super(props);
this.state ={
title: '',
posts:[],
loading:true
}
}
componentWillMount() {
this.props.GetPosts();
}
componentWillReceiveProps(nextProps, prevState) {
let hasNewLike = true;
if (prevState.posts && prevState.posts.length) {
for (let index = 0; index < nextProps.myPosts.length; index++) {
if (nextProps.myPosts[index].Likes.length !== prevState.posts[index].Likes.length) {
hasNewLike = true;
}
}
}
if (hasNewLike) {
this.setState({posts: nextProps.myPosts, loading: false}); // here we are updating the posts state if redux state has updated value of likes
}
}
// Return a new function. Otherwise the DeletePost action will be dispatch each
// time the Component rerenders.
removePost = (id) => () => {
this.props.DeletePost(id);
}
onChange = (e) => {
e.preventDefault();
this.setState({
title: e.target.value
})
}
formEditing = (id) => ()=> {;
this.props.EditChange(id);
}
render(){
const { posts, loading} = this.state;
// console.log(this.props.posts)
// console.log(this.props.ourLikes);
if(loading){
return "loading..."
}
return (
<div>
{this.state.posts.map(post => (
<Paper key={post.id} style={Styles.myPaper}>
<PostItem
myLikes={post.Likes.length} // right here
myTitle={this.state.title}
editChange={this.onChange}
editForm={this.formEditing}
isEditing={this.props.isEditingId === post.id}
removePost={this.removePost}
{...post}
/>
</Paper>
))}
</div>
);
}
}
const mapStateToProps = (state) => ({
isEditingId: state.post.isEditingId,
myPosts: state.post.posts,
})
const mapDispatchToProps = (dispatch) => ({
// pass creds which can be called anything, but i just call it credentials but it should be called something more
// specific.
GetPosts: () => dispatch(GetPosts()),
EditChange: (id) => dispatch(EditChange(id)),
UpdatePost: (creds) => dispatch(UpdatePost(creds)),
postLike: (id) => dispatch( postLike(id)),
// Pass id to the DeletePost functions.
DeletePost: (id) => dispatch(DeletePost(id))
});
// without withRouter componentWillReceiveProps will not work like its supposed too.
export default withRouter(connect(mapStateToProps,mapDispatchToProps)(PostList));
render() {
const {loading} = this.state;
const {myPosts} = this.props
console.log(this.state.posts);
if (!this.props.isAuthenticated) {
return (<Redirect to='/signIn'/>);
}
if (loading) {
return "loading..."
}
return (
<div className="App" style={Styles.wrapper}>
<h1>Posts</h1>
{/* <PostList posts={this.state.posts}/> */}
<div>
{this.state.posts.map(post => (
<Paper key={post.id} style={Styles.myPaper}>
<PostItem myLikes={post.Likes.length} // right here
myTitle={this.state.title} editChange={this.onChange} editForm={this.formEditing} isEditing={this.props.isEditingId === post.id} removePost={this.removePost} {...post}/>
</Paper>
))}
</div>
</div>
);
}
}
Posts.js
import React, { Component } from 'react';
import Paper from '@material-ui/core/Paper';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import moment from 'moment';
import Editable from './Editable';
import {connect} from 'react-redux';
import {UpdatePost, postLike, getCount} from '../actions/';
import Like from './Like';
import Axios from '../Axios';
const Styles = {
myPaper: {
margin: '20px 0px',
padding: '20px'
},
button:{
marginRight:'30px'
}
}
class PostItem extends Component{
constructor(props){
super(props);
this.state = {
disabled: false,
myId: 0,
likes:0
}
}
onUpdate = (id, title) => () => {
// we need the id so expres knows what post to update, and the title being that only editing the title.
if(this.props.myTitle !== null){
const creds = {
id, title
}
this.props.UpdatePost(creds);
}
}
render(){
const {title, id, userId, removePost, createdAt, post_content, username, editForm, isEditing, editChange, myTitle, postUpdate, Likes, clickLike, myLikes} = this.props
return(
......
{/* likes get like counts */}
<Like like={id} likes={myLikes} />
.......
....
clickLike = (id) => {
this.props.postLike(id);
// toggles between css class
this.setState({
heart: !this.state.heart
})
}
render(){
return(
<div style={{float:'right', fontSize: '1.5em', color:'tomato'}} >
<i style={{ marginRight: '140px'}} className={this.state.heart ? 'fa fa-heart':'fa fa-heart-o' }>
<span style={{ marginLeft: '6px'}}>
<a href="#" onClick={() =>this.clickLike(this.props.like)}>Like</a>
</span>
{/* gets the like counts */}
<span style={{ marginLeft: '7px'}} >{this.props.likes} </span>
</i>
</div>
)
}
}
const mapStateToProps = (state) => ({
})
const mapDispatchToProps = (dispatch) => ({
postLike: (id) => dispatch( postLike(id))
// Pass id to the DeletePost functions.
});
export default connect(null, mapDispatchToProps)(Like);
4 Réponses :
Cela n'a probablement pas grand-chose à voir avec la logique que vous avez mise en place et plus avec le balisage html lui-même. Si vous deviez prendre l'événement et le consigner dans console.log, vous constaterez probablement que vous ne touchez pas réellement la balise au premier clic, mais l'un de ses éléments extérieurs. Essayez d'encapsuler la balise et tout ce qui se trouve à l'intérieur dans une balise, puis de mettre la logique onClick dans le bouton à la place et vous obtiendrez de meilleurs résultats.
<div style={{float:'right', fontSize: '1.5em', color:'tomato'}} >
<button onClick={() =>this.clickLike(this.props.like)}>
<i style={{ marginRight: '140px'}} className={this.state.heart ? 'fa fa-heart':'fa fa-heart-o' }>
<span style={{ marginLeft: '6px'}}>
<a href="#">Like</a>
</span>
{/* gets the like counts */}
<span style={{ marginLeft: '7px'}} >{this.props.likes} </span>
</i>
</button>
div>
désolé pour la réponse tardive va essayer ceci. Merci encore .
ouais, c'est la même chose. ne tirant qu'après avoir cliqué deux fois.
Vous devez être prudent lorsque vous utilisez des fonctions fléchées avec le mot-clé this car il ne fait pas référence à l'objet courant, mais à son objet parent à la place.
Et c'est exactement ce que le PO voudrait.?.
Essayez de faire comme ça:
clickLike = (id) => () => {
this.props.postLike(id);
// toggles between css class
this.setState({
heart: !this.state.heart
})
}
<a href="#" onClick={this.clickLike(this.props.like)}>Like</a>
désolé pour la réponse tardive, cela n'a pas non plus résolu le problème.
fait une mise à jour. le composant similaire est dans un composant enfant.
Où avez-vous accès au composant postLike on Like? Sur ton code, je ne peux pas le voir comme un accessoire
J'ai fait une modification désolé de ne pas l'inclure. Le poste comme est appelé à coup sûr.
Votre code semble correct, essayez d'ajouter une console.log sur vos actions pour voir si elle est appelée correctement
le console.log s'affiche dès qu'il est cliqué et le backend fonctionne en un seul clic. C'est juste le décompte qui ne se met pas à jour en un seul clic, souhaitez-vous voir le componentWillReceiveProps ?
J'ai vu votre code et probablement votre problème est votre façon de récupérer les messages. Chaque fois que vous cliquez sur "J'aime", vous pouvez envoyer une action qui met à jour votre compteur, lorsque vous l'avez fait, vous pouvez mettre à jour votre état de publication local (comme la mise à jour de la liste actuelle) ou vous pouvez récupérer une API puis récupérer la PostList. Vous devez être prudent lors de l'envoi de cette action car vous devez mettre à jour votre liste à chaque fois que vous envoyez l'action similaire. MAIS, vous pouvez simplement envoyer l'action qui déclenche le semblable et si elle a réussi, vous pouvez utiliser setState pour voter pour le bouton semblable.
Essayez également d'ajouter votre projet à github, puis utilisez le codeandbox pour le récupérer. Exemple: codesandbox.io/s/github/victorsilent/todo-list-react-redux Comment faire: codesandbox.io/s/github/YOURUSER/REPOSITORY-NAME
merci d'avoir partagé le bac à sable. Je vais l'utiliser pour résoudre la solution, j'ai accepté votre réponse pour le moment. Merci.
Essayez de coller votre bac à sable aussi, il sera plus facile de vous aider :)
<span style={{ marginLeft: '6px'}} onClick=
{()=>this.clickLike(this.props.like)}>
<a href="#" >Like</a>
</span>
désolé pour la réponse tardive cela n'a pas résolu le problème. :(
merci pour la réponse, mais la solution n'a pas fonctionné. J'ai fait une mise à jour.
Je vais faire une modification