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);
Related
For some reason, when i render InventoryItem component inside InventoryPage component, dispatch is returned as undefined, but when i render it inside any other component it works perfectly.
Here's InventoryItem:
// REDUX
import { connect } from 'react-redux';
import { addItem } from '../../../Redux/reducers/cart/actions/cartActions.js';
// REUSABLE COMPONENTS
import { Button } from '../button/button.jsx';
export const InventoryItem = ({ drilledProps, dispatch }) => {
const { name, price, imageUrl } = drilledProps;
return (
<div className="collection-item">
<div
className="image"
style={{
background: `url(${imageUrl})`
}}
/>
<div className="collection-footer">
<span className="name">{name}</span>
<span className="price">${price}</span>
</div>
<Button
handler={() => dispatch(addItem(drilledProps))}
modifier="_inverted"
type="button"
text="ADD TO CART"
/>
</div>
);
};
export default connect(null)(InventoryItem);
When i render it here, dispatch returns undefined:
// REDUX
import { connect } from 'react-redux';
import { categorySelector } from '../../../../Redux/reducers/inventory/selectors/inventorySelectors.js';
// COMPONENTS
import { InventoryItem } from '../../../reusable-components/inventory-item/inventory-item.jsx';
const InventoryPage = ({ reduxProps: { categoryProps } }) => {
const { title: category, items } = categoryProps;
return (
<div className="collection-page">
<h2 className="title">{category}</h2>
<div className="items">
{
items.map((item) => (
<InventoryItem key={item.id} drilledProps={item}/>
))
}
</div>
</div>
);
};
const mapStoreToProps = (currentStore, ownProps) => ({
reduxProps: {
categoryProps: categorySelector(ownProps.match.params.categoryId)(currentStore)
}
});
export default connect(mapStoreToProps)(InventoryPage);
When i render it here it works perfectly:
// COMPONENTS
import InventoryItem from '../../../../reusable-components/inventory-item/inventory-item.jsx';
export const InventoryPreview = ({ title, items }) => {
return (
<div className="collection-preview">
<h1 className="title">{title}</h1>
<div className="preview">
{items
.filter((item, index) => index < 4)
.map((item) => (
<InventoryItem key={item.id} drilledProps={item} />
))}
</div>
</div>
);
};
Thanks for the help in advance!
You are importing the unconnected component, the connected component exports as default so you should do:
//not import { InventoryItem }
import InventoryItem from '../../../../reusable-components/inventory-item/inventory-item.jsx';
when you do export const InventoryItem = then you import it as import {InventoryItem} from ... but when you import the default export: export default connect(... then you import it as import AnyNameYouWant from ...
Note: please pull the repo to get access to the full App, there are too many files to simply share the code here. The repo: https://github.com/liviu-ganea/movie-database.git
So I've asked a question previously about my first React + Redux app and I've improved it. I got 2 problems now. The delete function for each movie (i.e. each entry in the redux state) is working just fine. So I now have problems with Login. Every time I press the button, nothing happens, and I suspect it's because the Login page component receives no props from the redux state.
My reasoning:
handleCLick = () => {
let userName = this.props.user.nickname;
let pw = this.props.user.password;
const nicknameBox = document.getElementById('nickname').textContent;
const passwordBox = document.getElementById('password').textContent.trim;
/*if (nicknameBox === userName && passwordBox === pw) {*/
this.props.loginUser((this.props.user.isLoggedIn = true));
this.props.history.push('/');
//}
};
When commented as it is now, it should go to the home page whenever I click the login button and if the password matches doesn't matter. Only there is no reaction to me pressing the button. Is the problem as I suspect?
And another problem: see in Movie.js I've tried to get the path (it's set in state: movies: cover) to the movie poster (located in ./src) so that when (or if) I make use of an API the path should set itself dynamically (i.e. I won't have to go into every component and add the path manually). Same thing on the Home page (./src/Components/Routes/Home.js)...no posters for any movie.
After Comments:
Component:
import React, { Component } from 'react';
import './routes.css';
import { loginAction } from '../../actions/userActions';
import { connect } from 'react-redux';
class Login extends Component {
handleCLick = () => {
let userName = this.props.user.nickname;
let pw = this.props.user.password;
const nicknameBox = document.getElementById('nickname').textContent;
const passwordBox = document.getElementById('password').textContent.trim;
/*if (nicknameBox === userName && passwordBox === pw) {*/
this.props.loginUser((this.props.user.isLoggedIn = true));
this.props.history.push('/');
//}
};
render() {
console.log(this.props);
return (
<div className="container page-container login-page">
<h3 className="page-title">Log In User</h3>
<div className="login-box">
<div>
<label className="login-labels" htmlFor="nickname">
Login{' '}
</label>
<input type="text" className="nickname-box" name="nickname" id="nickname" />
</div>
<div>
<label className="login-labels" htmlFor="password">
Password{' '}
</label>
<input type="password" className="password-box" name="password" id="pasword" />
</div>
<button className="login-button" onClick={this.handleClick}>
Login
</button>
</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
user: state.user,
};
};
const mapDispatchToProps = (dispatch) => {
return {
loginUser: (isLoggedIn) => {
dispatch(loginAction(isLoggedIn));
},
};
};
export default connect(mapDispatchToProps, mapStateToProps)(Login);
Reducer:
import { createStore } from 'redux';
const initialState = {
movies: [
{
id: '1',
title: 'John Wick Chapter 2',
year: '2017',
main_actor: 'Keanu Reeves',
summary: `The hitman that's been retired then back then retired strikes again, this time against the Mafia.`,
cover: '../john_wick_2.jpg',
},
{
id: '2',
title: 'Star Wars Revenge of the Sith',
year: '2005',
main_actor: 'Ewan McGregor',
summary: `Anakin betrays Space Jesus so General Kenobi is forced to Mustafar Anakin.`,
cover: '../sw_rots.png',
},
{
id: '3',
title: 'Star Wars The Clone Wars',
year: '2008 - 2020',
main_actor: 'Ewan McGregor, Hayden Christensen',
summary: `Yoda has finally overdosed on Ketamine, Mace Window hasn't been defenestrated yet and The Negotiator has proven himself incapable of falling to the Dark Side`,
cover: '../sw_tcw.jpg',
},
],
user: {
isLoggedIn: 'false',
nickname: 'obi_wan',
password: '12345',
},
};
const rootReducer = (state = initialState, action) => {
switch (action.type) {
case 'DELETE_MOVIE':
let newMovieList = state.movies.filter((movie) => {
return action.id !== movie.id;
});
return {
...state,
movies: newMovieList,
};
case 'LOG_IN':
let newUserState = action.isLoggedIn;
return {
...state,
user: { ...state.user, isLoggedIn: action.payload.isLoggedIn },
};
default:
return state;
}
return state;
};
export default rootReducer;
userActions:
export const loginAction = (isLoggedIn) => {
return {
type: 'LOG_IN',
isLoggedIn: 'true',
};
};
index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import rootReducer from './reducers/rootReducer';
import App from './App';
const store = createStore(rootReducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root'),
);
console.log(this.props) for the Login component:
[![enter image description here][1]][1]
Movie.js:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { deleteMovieAction } from '../actions/movieActions';
import './Routes/routes.css';
class Movie extends Component {
handleClick = () => {
this.props.deleteMovie(this.props.movie.id);
this.props.history.push('/');
};
render() {
console.log(this.props);
const isUser = this.props.user.isLoggedIn ? (
<button className="delete-movie-button" onClick={this.handleClick}>
Delete
</button>
) : null;
const theMovie = this.props.movie ? (
<div className="movie-container">
<img src={this.props.movie.cover} alt={this.props.movie.title} className="movie-cover" />
<div className="movie-container-content">
<h2 className="movie-title">{this.props.movie.title}</h2>
<p className="movie-description">{this.props.movie.summary}</p>
<div className="movie-data">
<p className="movie-year">{this.props.movie.year}</p>
<p className="movie-actor">{this.props.movie.main_actor}</p>
</div>
</div>
{isUser}
</div>
) : (
<div className="center">Getting data about the movie. Please wait.</div>
);
return <div className="container page-container">{theMovie}</div>;
}
}
const mapStateToProps = (state, ownProps) => {
let id = ownProps.match.params.movie_id;
return {
user: state.user,
movie: state.movies.find((movie) => movie.id === id),
};
};
const mapDispatchToProps = (dispatch) => {
return {
deleteMovie: (id) => {
dispatch(deleteMovieAction(id));
},
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Movie);
Movie.js - every movie component
import React, {Component} from 'react'
import { connect } from 'react-redux';
import { deleteMovieAction } from '../actions/movieActions'
import './Routes/routes.css'
class Movie extends Component {
handleClick = () => {
this.props.deleteMovie(this.props.movie.id);
this.props.history.push('/');
}
render () {
const coverino = ''
console.log(this.props);
const isUser = this.props.isLoggedIn ? ( <button className='delete-movie-button' onClick={this.handleClick}>Delete</button> ) : (null)
const theMovie = this.props.movie ? (
<div className='movie-container'>
<img src={this.props.movie.cover} alt={this.props.movie.title} className='movie-cover'/>
<div className='movie-container-content'>
<h2 className='movie-title'>{this.props.movie.title}</h2>
<p className='movie-description'>{this.props.movie.summary}</p>
<div className='movie-data'>
<p className='movie-year'>{this.props.movie.year}</p>
<p className='movie-actor'>{this.props.movie.main_actor}</p>
</div>
</div>
{isUser}
</div>
) : ( <div className="center">Getting data about the movie. Please wait.</div> );
return (
<div className='container page-container'>
{theMovie}
</div>
)
}
}
const mapStateToProps = (state, ownProps) => {
let id = ownProps.match.params.movie_id;
return {
isLoggedIn: state.user.isLoggedIn,
movie: state.movies.find(movie => movie.id === id),
}
}
const mapDispatchToProps = (dispatch) => {
return {
deleteMovie: (id) => { dispatch(deleteMovieAction(id))}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Movie)
The page display the entire movie list
import React, {Component} from 'react'
import { Link } from 'react-router-dom'
import { connect } from 'react-redux'
import './routes.css'
class Home extends Component{
render() {
console.log(this.props);
const { movies } = this.props;
const movieList = movies.length ? ( movies.map(movie => {
return (
<Link to={'/' + movie.id} key={movie.id}>
<div className='movie-container'>
<img src={require(`${movie.cover}`)} alt={movie.title} className='movie-cover'/>
<div className='movie-container-content'>
<h2 className='movie-title'>{movie.title}</h2>
<p className='movie-description'>{movie.summary}</p>
<div className='movie-data'>
<p className='movie-year'>{movie.year}</p>
<p className='movie-actor'>{movie.main_actor}</p>
</div>
</div>
</div>
</Link>
)
}
, )) : (<div className='waiting-for-movies'>Loading. Please wait</div>)
return (
<div className='container page-container'>
{movieList}
</div>
)
}
}
const mapStateToProps = (state) => {
return {
movies: state.movies
}
}
export default connect(mapStateToProps)(Home)
neither the require method, nor the simple {this.props...} works
[1]: https://i.stack.imgur.com/51FTy.png
So, as the title suggests, Cards component is receiving props from UserPosts, as well as it's connected to the store to dispatch an action. But it looks like this is not working at all. Connecting a component is not working for me. Maybe I am missing something? Can someone show me the correct way to do it. I'm trying to delete a post on clicking on the delete button.
Here is the code.
UserPosts
import React, { Component } from "react"
import { getUserPosts, getCurrentUser } from "../actions/userActions"
import { connect } from "react-redux"
import Cards from "./Cards"
class UserFeed extends Component {
componentDidMount() {
const authToken = localStorage.getItem("authToken")
if (authToken) {
this.props.dispatch(getCurrentUser(authToken))
if (this.props && this.props.userId) {
this.props.dispatch(getUserPosts(this.props.userId))
} else {
return null
}
}
}
render() {
const { isFetchingUserPosts, userPosts } = this.props
return isFetchingUserPosts ? (
<p>Fetching....</p>
) : (
<div>
{userPosts &&
userPosts.map(post => {
return <Cards key={post._id} post={post} />
})}
</div>
)
}
}
const mapStateToPros = state => {
return {
isFetchingUserPosts: state.userPosts.isFetchingUserPosts,
userPosts: state.userPosts.userPosts,
userId: state.auth.user._id
}
}
export default connect(mapStateToPros)(UserFeed)
Cards
import React, { Component } from "react"
import { connect } from "react-redux"
import { deletePost } from "../actions/userActions"
class Cards extends Component {
handleDelete = postId => {
this.props.dispatch(deletePost(postId))
}
render() {
const { _id, title, description } = this.props.post
return (
<div className="card">
<div className="card-content">
<div className="media">
<div className="media-left">
<figure className="image is-48x48">
<img
src="https://bulma.io/images/placeholders/96x96.png"
alt="Placeholder image"
/>
</figure>
</div>
<div className="media-content" style={{ border: "1px grey" }}>
<p className="title is-5">{title}</p>
<p className="content">{description}</p>
<button className="button is-success">Edit</button>
<button
onClick={this.handleDelete(_id)}
className="button is-success"
>
Delete
</button>
</div>
</div>
</div>
</div>
)
}
}
const mapStateToProps = () => {
return {
nothing: "nothing"
}
}
export default connect(mapStateToProps)(Cards)
deletePost
export const deletePost = (id) => {
return async dispatch => {
dispatch({ type: "DELETING_POST_START" })
try {
const deletedPost = await axios.delete(`http://localhost:3000/api/v1/posts/${id}/delete`)
dispatch({
type: "DELETING_POST_SUCCESS",
data: deletedPost
})
} catch(error) {
dispatch({
type: "DELETING_POST_FAILURE",
data: { error: "Something went wrong" }
})
}
}
}
Should be something like this:
const mapDispatchToProps(dispatch) {
return bindActionCreators({ deletePost }, dispatch)
}
export default connect(mapStateToProps, mapDispatchToProps)(Cards)
And then call it as a prop:
onClick={this.props.deletePost(_id)}
import React, { Fragment, useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';
import { getPosts } from '../redux/actions/#posts';
import PostItem from '../components/posts/PostItem';
import CommentForm from '../components/posts/CommentForm';
import Comment from '../components/posts/Comment';
import '../styles/posts/postComponent.scss';
const Posts = ({
getPosts,
posts: { posts, isLoading },
isAuthenticated,
user
}) => {
useEffect(() => {
getPosts();
}, []);
const [show, toggleShow] = useState(false);
console.log(show);
const postsList = isLoading ? (
<div>posts are loading</div>
) : (
posts.map(post => {
return (
<div className='post'>
<PostItem
key={post._id}
auth={isAuthenticated}
user={user}
id={post._id}
title={post.title}
body={post.text}
author={post.name}
avatar={post.avatar}
date={post.date}
likes={post.likes}
comments={post.comments.map(comment => comment)}
toggleShow={toggleShow}
show={show}
/>
<CommentForm id={post._id} />
{post.comments.map(
comment =>
show && (
<Comment
key={comment._id}
comment={comment}
auth={isAuthenticated}
admin={user}
show={show}
/>
)
)}
</div>
);
})
);
return (
<Fragment>
<Link to='/add-post'>add Post</Link>
<div>{postsList}</div>
</Fragment>
);
};
Posts.propTypes = {
getPosts: PropTypes.func.isRequired,
posts: PropTypes.object.isRequired,
isAuthenticated: PropTypes.bool.isRequired
};
const mapStateToProps = state => {
// console.log(state.posts.posts.map(post => post.likes));
// console.log(state);
return {
posts: state.posts,
isAuthenticated: state.auth.isAuthenticated,
user: state.auth.user
};
};
export default connect(mapStateToProps, { getPosts })(Posts);
import React, { Fragment } from 'react';
import '../../styles/posts/postComponent.scss';
const Comment = ({
comment: { user, avatar, name, date, text },
admin,
auth
}) => {
return (
<Fragment>
<div className='c-container'>
<div className='c-img-text'>
<img className='c-img' height={'40px'} src={avatar} />
<div className='c-nt'>
<a href='#' className='c-n'>
{name}
</a>
<span className='c-t'> {text}</span>
<i className='c-d'>{date}</i>
</div>
{auth && admin
? admin._id === user && <div className='c-toggle'>...</div>
: ''}
</div>
</div>
</Fragment>
);
};
export default Comment;
I have a list of posts stored in redux, and mapped through it to create components. Now each component has a some body and comments.
I want to show the comments only after onClick event .
Below is the code I have come up with , and on Click it is toggling all the comments of all the Components.How can I toggle comments of an individual Component.
I have the problem when I use the Reactjs, I'm really new to Reactjs, so maybe it's a easy problem
I want to use the class ClickButton in the UserInfo,but I don't know how to change the name through props
import React, { PropTypes } from 'react';
import { Button } from 'antd';
import { connect } from 'react-redux';
import styles from './ClickButton.less';
const ClickButton = ({ todos,dispatch }) => {
const userinforclick = () => {
dispatch({
type: 'todos/clickbutton',
payload: !todos['click_button'],
});
};
return (
<span>
< span type="primary" className={ styles.show } onClick={ userinforclick.bind(this) } > {this.props.name} < /span >
</span>
);
};
function clickbutton({ todos }){
return{
todos:todos,
}
}
export default connect(clickbutton)(ClickButton)
and i use the ClickButton in UserInfo:
import React from 'react'
import styles from './Userinfo.less'
import ClickButton from '../../components/Button/ClickButton'
import { connect } from 'react-redux';
import { Spin } from 'antd'
const Userinfo = ({ todos,dispatch }) => {
const { userinfo, userinfoloading, click_button } = todos;
if(userinfoloading) {
return <Spin />;
}
const renderList = () => {
return(
<div className={ styles.userInfodiv}>
<div>
<span className={ styles.userInfoTitle }>userinfo</span>
</div>
<div className = { styles.slice }></div>
<div className = { styles.userInfoBody}>
<div className = { styles.userInfoSubBody }>
<span>username:</span>
<span>{userinfo[0]['username']}</span>
</div>
<div className = { styles.userInfoSubBody }>
<span>number:</span>
{ click_button ? <span>{userinfo[0]['phone']}</span> : <input type="text" value={userinfo[0]['phone']} /> }
<ClickButton name="john" />
</div>
</div>
</div>
);
};
return (
<div>
{ renderList() }
</div>
);
};
function mapStateToProps({ todos }) {
return {
todos: todos,
};
}
export default connect(mapStateToProps)(Userinfo);
Here's something that actually works (although I removed the todos and such but you can add them in easily):
class RenderList extends React.Component {
render() {
return (<span> {this.props.name} </span>);
}
}
class App extends React.Component {
render() {
return (<div>
<RenderList name="John"/>
</div>)
}
}
ReactDOM.render(<App/>,document.getElementById("app"));