Changes are not reflected in UI in react - reactjs

When a user like a post, then the count is incremented in ui. Bu when a user remove the like then count ui is not changing though it is changed in server.How to solve it?
When a user like a post, then the count is incremented in ui. Bu when a user remove the like then count ui is not changing though it is changed in server.How to solve it?
import React from 'react';
import moment from 'moment';
import CommentForm from './CommentForm';
import CommentList from './CommentList';
import CommentModal from './CommentModal';
import { connect } from 'react-redux';
import { startAddComment, startAddLike, startRemoveLike } from
'../actions/post';
import { Link } from 'react-router-dom';
import UserInfo from './UserInfo';
class PostListItem extends React.Component{
constructor(props){
super(props);
this.state = {
isliked: false,
commentM: undefined,
likes: this.props.likes
}
}
componentDidMount(){
if(this.props.likes.includes(this.props.user.uid)){
this.setState(() => ({isliked:true}));
}
}
onClickedLike = () =>{
if(this.state.isliked === false){
this.props.dispatch(startAddLike(this.props._id));
this.setState(()=>{
console.log(this.props);
return{
isliked:true
}
});
} else{
this.props.dispatch(startRemoveLike(this.props._id));
this.setState(()=>({isliked:false}));
}
}
openModal = () =>{
this.setState({commentM: this.props.comments});
}
closeModal = () =>{
this.setState(({commentM: undefined}));
}
render(){
return(
<div className="post">
<div className="post__header">
<UserInfo user={this.props.author}
time={this.props.createdAt}/>
{
(this.props.user.uid === this.props.author.uid)?
<Link to={`/edit/${this.props._id}`}
className="post__edit">
Edit</Link>:''
}
{/* <p className="post__time">
{moment(this.props.createdAt).fromNow()}</p> */}
</div>
<div className="post__caption">{this.props.caption}</div>
<img src={this.props.content} className="post__content"/>
<div className="post__extra">
<div className="post__lc">
<button className="post__button"
onClick={this.onClickedLike}
>{this.state.isliked? <i className="fas fa-futbol"></i>
: <i className="far fa-futbol"></i>}
</button>
<button className="post__button"
onClick={this.openModal}><i className="far fa-
comment"></i>
</button>
</div>
{this.props.likes.length !== 0 && <p className="post__like">
{this.props.likes.length} {this.props.likes.length === 1? 'like':'likes'}
</p>} // likes count is not changing while removing the like(ui only)
<CommentModal
commentM={this.state.commentM}
closeModal={this.closeModal}/>
<CommentForm onSubmit={(comment) => {
this.props.dispatch(startAddComment(this.props._id,
comment));
}} />
{this.props.comments && <CommentList comments=
{this.props.comments}/>}
</div>
</div>
);
}
};
const mapStateToProps = (state) => {
return{
user: state.auth
}
}
export default connect(mapStateToProps)(PostListItem);

Related

reactjs Modal not being called

Hi everyone I am new to react but have the task to implement this modal. Unfortunately If I click on the button nothing happens. I could not find a solution and to my total confusion it seems like there are many different ways to implement this kind of modals.
Does anyone have a suggestion please?
The modal itself:
import React, { useState } from 'react'
import './BookingUpdate.css';
function Modal({ setOpenModal, children } : {setOpenModal:any, children:any}) {
if(!setOpenModal) return null;
return (
<div className="modalBackground">
<div className="modalContainer">
<div className="titleCloseBtn">
<button
onClick={() => {
setOpenModal(false);
}}
>
X
</button>
</div>
<div className="title">
<h1>Are You Sure You Want to Continue?</h1>
</div>
<div className="body">
<p>The next page looks amazing. Hope you want to go there!</p>
</div>
<div className="footer">
<button
onClick={() => {
setOpenModal(false);
}}
id="cancelBtn"
>
Cancel
</button>
<button>Continue</button>
</div>
</div>
</div>
);
}
export default Modal;
The file from which it is called:
import React, { useState } from 'react';
import FullLayout from '../components/FullLayout';
import Loading from '../components/Loading';
import { Booking, Formatting } from 'flexspace-commons';
import { Table, Form, Col, Row, Button } from 'react-bootstrap';
import { Search as IconSearch, Download as IconDownload, X as IconX , Settings as IconSettings } from 'react-feather';
import ExcellentExport from 'excellentexport';
import { withTranslation } from 'react-i18next';
import { TFunction } from 'i18next';
import type * as CSS from 'csstype';
import Modal from "../components/BookingUpdate";
interface State {
loading: boolean
start: string
end: string
modalIsOpen: boolean
}
interface Props {
t: TFunction
}
class Bookings extends React.Component<Props, State> {
data: Booking[];
constructor(props: any) {
super(props);
this.data = [];
let end = new Date();
let start = new Date();
start.setDate(end.getDate() - 7);
this.state = {
loading: true,
start: Formatting.getISO8601(start),
end: Formatting.getISO8601(end),
modalIsOpen: false
};
this.toggleBookingModal = this.toggleBookingModal.bind( this );
}
.
.
.
toggleBookingModal = (booking: Booking) => {
this.setState( { modalIsOpen: ! this.state.modalIsOpen } );
<Modal setOpenModal={this.state.modalIsOpen} >
</Modal>
}
renderItem = (booking: Booking) => {
const btnStyle: CSS.Properties = {
['padding' as any]: '0.1rem 0.3rem',
['font-size' as any]: '0.875rem',
['border-radius' as any]: '0.2rem',
};
return (
<tr key={booking.id}>
<td>{booking.user.email}</td>
<td>{booking.space.location.name}</td>
<td>{booking.space.name}</td>
<td>{Formatting.getFormatterShort().format(booking.enter)}</td>
<td>{Formatting.getFormatterShort().format(booking.leave)}</td>
<td><Button variant="info" style={btnStyle} onClick={() => this.toggleBookingModal(booking)}><IconSettings className="feather" /></Button></td>
<td><Button variant="danger" style={btnStyle} onClick={() => this.cancelBooking(booking)}><IconX className="feather" /></Button></td>
</tr>
);
}
.
.
.

How to add button cart in shopping cart react redux?

how to add an action when the add button is clicked then the item will display the product?
This code does not display the product when clicked
I've been fiddling with it but it's still an error, who knows, someone here can help me and fix the code and explain it
cartAction.js
import {ADD_TO_CART} from './ActionType';
export const addToCart = (items) =>{
return{
type: ADD_TO_CART,
items //I'm confused about what to do in the action payload here
}
}
cartReducer.js
import ImgT from './images/image-product-1-thumbnail.jpg';
import {ADD_TO_CART} from './ActionType';
const initState = {
items: [
{id:1,title:'title',
brand:cc',
images:ImgT,
desc:'helo world',
price:125.00}
],addItems:[],
total:0
}
const cartReducer= (state = initState,action)=>{
if(action.type === ADD_TO_CART){
return {...state, addItems:state.addItems} //I'm confused about what to do in the action payload here
}
return state
}
export default cartReducer;
cart.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
class Cart extends Component {
render() {
return (
<div>
{this.props.Items.map(item =>{
<div key={item.id}>
{/* <img src={item.images} /> */}
<p>{item.title}</p>
<h4>brand: {item.brand}</h4>
<p>{item.price}</p>
</div>
})
}
</div>
);
}
}
const mapToProps = (state ) =>{
return{
Items:state.addItems}
}
export default connect(mapToProps)(Cart);
Home.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import Cart from './Cart';
import {addToCart} from './cartAction';
class Home extends Component{
handleClick = () =>{
this.props.addToCart()
}
render(){
let item = this.props.items.map(item =>{
return(
<div className='card' key={item}>
<img style={{width:'10rem'}} src={item.images}/>
<p className='card-title '>{item.title}</p>
<h2 className='card-title fs-4'>{item.brand}</h2>
<button onClick={() => this.handleClick()} className='btn btn-primary'>Add to cart</button>
<h3 className='fs-5'>{item.price}</h3>
</div>
)
})
return(
<div className="container">
<h3>Home</h3>
{item}
<Cart/>
</div>
)
}
}
const mapToProps = (state) => {
return{
items:state.items,
}
}
const mapDispatchToProps = (dispatch) => {
return{
addToCart: () => dispatch(addToCart())}
}
export default connect(mapToProps,mapDispatchToProps)(Home);

How to redirect to another page in react confirmAlert?

I am developing a react shopping cart app. If the user click on 'Clear Cart' button, the entire cart will be cleared. Before that the application should confirm the action and therefore, I used 'React Confirm Alert'. If the user click on 'Yes' button, it will clear the cart and it should navigate to the root page('/'). I searched over the internet and on the StackOverflow and tried the three ways given here. But nothing worked. For both this.props.history.push('/') and this.props.router.push('/') gives me a TypeError saying undefined object and for useHistory() it says violating react hooks principles. Is there anything I can do to make this work? Thanks in advance!
Code :-
import React, { useEffect, useState, Component} from 'react';
import Titles from "../Titles";
import CartColumns from './CartColumns';
import EmptyCart from "./EmptyCart";
import CartList from "./CartList";
import {connect} from "react-redux";
import {Link, Redirect} from "react-router-dom";
import Axios from "axios";
import { confirmAlert } from 'react-confirm-alert'; // Import
import 'react-confirm-alert/src/react-confirm-alert.css' // Import css
const mapStateToProps = ({ session, history}) => ({
session, history
});
class Cart extends Component {
constructor() {
super();
this.removeItem = this.removeItem.bind(this);
}
state = {
Cart: [],
total : 0,
discount: 0
};
componentDidMount() {
if(this.props.session.userId !== null){
this.getItems();
}
}
getItems = () => {
//function to get the items
};
removeItem = (productId) => {
//method to remove an item
};
clearCart = () => {
confirmAlert({
title: 'Clear Cart',
message: 'Are you sure to clear the Cart?',
buttons: [
{
label: 'Yes',
onClick: () => {Axios.get('http://localhost:8000/api/cart/clearCart', {params:{userId: this.props.session.userId}});
} //I want to redirect from here
},
{
label: 'No'
}
]
})
};
checkout= () => {
//Checkout function
};
render() {
let total = this.state.total;
let discount = this.state.discount;
if(this.props.session.username !== null){
return (
<section>
{(this.state.Cart.length > 0) ? (
<React.Fragment>
<Titles name ="Your " title = "Cart">Cart</Titles>
<CartColumns/>
<CartList cart = {this.state.Cart} removeItem={this.removeItem}/>
<div className="container">
<div className="row">
<div className="col-10 mt-2 ml-sm-5 ml-md-auto col-sm-8 text-capitalize text-right">
<h5>
<span className="text-title">Sub Total: </span>
<strong>$ {total}</strong>
</h5>
<h5>
<span className="text-title">Discount: </span>
<strong>$ {discount}</strong>
</h5>
<h5>
<span className="text-title">Total: </span>
<strong>$ {total - discount}</strong>
</h5>
<div className="col-10 mt-2 ml-sm-5 ml-md-auto col-sm-8 text-capitalize text-right">
<button className="btn btn-outline-danger text-uppercase mb-3 px-5" type="button" onClick={this.clearCart}>Clear Cart</button>
<button className="btn btn-outline-info ml-3 text-uppercase mb-3 px-5" type="button" onClick={this.checkout}>Check Out</button>
</div>
</div>
</div>
</div>
</React.Fragment>
) : (
<EmptyCart/>
)
}
</section>
);
} else {
return(
<Redirect to="/login" />
);
}
}
}
export default connect(
mapStateToProps
)(Cart);
I think you have 2 options.
First: Just use window.location method like this
// Simulate a mouse click:
window.location.href = "http://www.example.com";
// Simulate an HTTP redirect:
window.location.replace("http://www.example.com");
Second: Use react state
import React from 'react'
import { Redirect } from 'react-router-dom'
class Cart extends Component {
constructor() {
super();
}
state = {
isRedirect: false
};
const onClick = () =>{
this.setState({isRedirect: true})
}
render() {
let isRedirect = this.state.isRedirect;
if(isRedirect == true){
return <Redirect to='/target' />
}
return (
<div>
...
</div>
)
)
}
window.location.replace("http://localhost:3000/");
This statement will solve your problem. Happy Coding!

TypeError: this.props.decrementCount is not a function

I am trying to make a simple cart counter but getting this error. I am confuse that mapStateToDispatch is working or not. Imported all modules,functions properly but getting only this error when i click the ADD,Remove button
import React,{Component} from 'react';
import './cart.css';
import {product,product1} from './product.js'
import 'bootstrap/dist/css/bootstrap.min.css';
import {incrementCount , decrementCount} from './actions/buttonBehave';
import {connect} from 'react-redux';
import { bindActionCreators } from 'redux'
export class Cart extends Component{
state = {
buttonClicked : false
}
handleButton= () =>{
this.setState({
buttonClicked : true
})
}
render()
{
return(
<div className="cardDiv">
<div className="card" >
<img className="card-img-top" src={product.image} alt="Card image" height="350px" />
<div className="card-body">
<h4 className="card-title">{product.name}</h4>
<p className="card-text">Model : {product.modelName}</p>
<p className="card-text">Price : {product.price}</p>
<a href="#" className="btn btn-primary " onClick={this.handleButton.bind(this)}> {this.state.buttonClicked ? "Add another" : "Add to cart"} </a>
<p className="card-text">Added : {this.props.count}</p>
<button onClick = { () => this.props.incrementCount ()}>Remove</button>
<button onClick = { () => this.props.decrementCount()}>ADD</button>
<p className="card-text">{this.props.count}</p>
</div>
</div>
</div>
);
}
}
const mapStateToProps= (state) =>{
return{
count : state.count
}
}
const mapDispatchToProps = () => {
return {
incrementCount,
decrementCount
}
}
export default connect(mapStateToProps,mapDispatchToProps())(Cart);
You are calling the function instead of passing its reference
export default connect(mapStateToProps,mapDispatchToProps())(Cart);
// ------------------------------------------------------^^--------
change to this
export default connect(mapStateToProps, mapDispatchToProps)(Cart);
An alternative is to just not use mapDispatchToProps at all and use the dispatch your connected component receives
export default connect(mapStateToProps)(Cart);
and then using dispatch
this.props.dispatch(decrementCount())

React - show menu when clicking on just one item from iterating item

I'm having problem with sliding menu in just one item.
When I click on the config button every item shows menu. I tried to figure out something by passing props {mail.id} but I'm afraid I don't understand this.
I would like to have sliding menu just in one item -- the clicked one.
This is ConfigButton
import React, { Component } from "react";
import './Menu.css';
class ConfigButton extends Component {
render() {
return (
<button className="configButton"
onClick={this.props.onClick}
>
<i className="configButtonIcon fas fa-cog"></i>
</button>
);
}
}
export default ConfigButton;
And this is the Component which renders:
import React, { Component } from 'react';
import { NavLink, HashRouter } from 'react-router-dom';
import axios from 'axios';
import Menu from './Menu';
import ConfigButton from './ConfigButton';
const API = myAPI;
const navLinkStyle = {
textDecoration: 'none',
color: '#123e57'
};
class Emails extends Component {
constructor(props) {
super(props);
this.state = {
visible: false,
mails: []
};
this.handleMouseDown = this.handleMouseDown.bind(this);
this.toggleMenu = this.toggleMenu.bind(this);
}
handleMouseDown(e) {
this.toggleMenu();
e.stopPropagation();
}
toggleMenu() {
this.setState({
visible: !this.state.visible
});
}
componentDidMount() {
axios.get(API)
.then(response => {
const mails = response.data;
this.setState({ mails });
})
}
truncate = (text, chars = 140) =>
text.length < chars ? text : (text.slice(0, chars) + '...')
render() {
let mails = this.state.mails;
console.log(mails);
mails = mails.map(mail => {
return (
<div key={mail.id}>
<div className='mail'>
{
!mails.displayed
? <i className="notDisplayed fas fa-circle"></i>
: <i className="displayed far fa-circle"></i>
}
<HashRouter>
<NavLink
to={`/openemail/${mail.id}`}
style={navLinkStyle}
>
<ul className='ulMailWrap'>
<div className='mailHeader'>
<li>{mail.sender}</li>
<li>{mail.created}</li>
</div>
<li>{mail.subject}</li>
<li>{this.truncate(mail.message)}</li>
</ul>
</NavLink>
</HashRouter>
<ConfigButton onClick={this.handleMouseDown} />
<Menu handleMouseDown={this.handleMouseDown}
menuVisibility={this.state.visible}
/>
</div>
</div>
)
});
return (
<div>
{ mails }
</div>
);
}
}
export default Emails;
You can pass a function that will send a different parameter to the handler, depending on value of each element in the array.
Do something like this:
...
<div key={mail.id} onClick={() => this.handleOpenMenu(mail.id)}>
...
Then at the handler:
handleOpenMenu = id => {
// do different stuffs on the id you get here
this.setState({ visibleMenuId: id });
}
And then change the props you are passing to your menu component:
<Menu menuVisibility={this.state.visibleMenuId === mail.id} />

Resources