I have a button that adds counters. It works but its a matter of UI structuring. When I click Add a counter, adds individual counters.
What I need is to have the independent counters, perhaps by programmatically the same result instead of onClick the button, having the +/- like <button> {counter} </button> directly.
What I have:
What I need (without clicking the above button):
When I click + or - then
TypeError: this.props.onIncrement is not a function
onClick
src/js/components/Posts.js:33
30 | <div>
31 | <span>{this.props.value}</span>
32 | <button
> 33 | onClick={() => this.props.onIncrement()}>
| ^ 34 | +
35 | </button>
Code:
Counter.js
// ./src/js/components/Counter.js
import React, { Component } from 'react';
class Counter extends Component {
render() {
return (
<div>
<span>{this.props.value}</span>
<button
onClick={() => this.props.onIncrement()}>
+
</button>
<button
onClick={() => this.props.onDecrement()}>
-
</button>
</div>
);
}
}
export default Counter;
Action
// ./src/js/actions/counters.js
export const increment = (id) => {
return {
type: "INCREMENT",
id
};
};
export const decrement = (id) => {
return {
type: "DECREMENT",
id
};
};
export const add_counter = () => {
return {
type: "ADD_COUNTER"
};
};
AddButton.js:
import React from 'react';
import { add_counter } from '../actions/counters';
import { connect } from 'react-redux';
const AddButton = ({dispatch}) => (
<button
onClick={() => {
dispatch(add_counter());
}}>
Add a counter
</button>
);
export default connect()(AddButton);
counterlist.js
// ./src/js/components/CounterList.js
import React from 'react';
import { connect } from 'react-redux';
import { increment, decrement } from '../actions/counters';
import Counter from './Counter';
const CounterList = ({
counters,
onIncrement,
onDecrement
}) => (
<ul>
{counters.map(counter =>
<Counter
key={counter.id}
value={counter.count}
onIncrement={() => onIncrement(counter.id)}
onDecrement={() => onDecrement(counter.id)}
/>
)}
</ul>
);
const mapStateToProps = (state) => {
return {
counters: state
};
};
const mapDispatchToProps = (dispatch) => {
return {
onIncrement: (id) => dispatch(increment(id)),
onDecrement: (id) => dispatch(decrement(id))
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(CounterList);
Posts.js
import React, {Component} from 'react';
import logo from '../../logo.svg';
import '../../App.css';
import { connect } from 'react-redux';
import Counter from './Counter'
import AddButton from './AddButton';
class Posts extends Component {
constructor(props) {
super(props);
this.state = {
response: ''
};
}
render() {
return (
<div className="App">
{Array.isArray(this.state.response) &&
this.state.response.map(resIndex => <div>
<AddButton/>
<Counter/>
{onIncrement(counter.id)}>
<h5> { resIndex.title } </h5>
<h5> { resIndex.body } </h5>
</div>
)}
</div>
)
}
}
export default connect()(Posts);
You can do what you want with Redux given what you have above, but you won't have access to your counter_id inside your Posts component to increment/decrement a given counter. You would need to somehow get that information into your Posts component, which is where you wanted to call increment/decrement programatically. This project would need restructured to resolve that issue. I would ditch Redux as it appears you're learning and I would focus on mastering state and props within React without Redux first.
This is how you would do it with Redux if you had access to a counter's ID. You'll pass into your component the increment/decrement functions as props by using the mapDispatchToProps function. You didn't have that in your Posts component which is why it was telling you your function was not defined. You have to have mapDispatchToProps for it to define the function on this.props.
I wasn't sure what you're doing to need to call this.props.onIncrement, so I just put it in componentDidMount for demonstration purposes.
import React, {Component} from 'react';
import { connect } from 'react-redux';
import Counter from './Counter';
import { increment, decrement } from '../actions/counters';
import AddButton from './AddButton';
class Posts extends Component {
constructor(props) {
super(props);
this.state = {
response: ''
};
}
componentDidMount() {
this.props.onIncrement(<your_counter_id>);
}
render() {
return (
<div className="App">
{Array.isArray(this.state.response) &&
this.state.response.map(resIndex => <div>
<AddButton/>
<Counter/>
<h5> { resIndex.title } </h5>
<h5> { resIndex.body } </h5>
</div>
)}
</div>
)
}
}
const mapDispatchToProps = (dispatch) => {
({
onIncrement: (id) => dispatch(increment(id)),
onDecrement: (id) => dispatch(decrement(id))
});
};
export default connect({}, mapDispatchToProps)(Posts);
Related
inside componentDidMount Im calling the dispatched fetchReviews. but once mounted how does the fetched reviews get set in props?
business show component:
import React from "react";
import { Link } from 'react-router-dom';
import Star from "../star/star";
class BusinessShowIndex extends React.Component {
constructor(props) {
super(props)
this.state = {
loading: true
}
}
componentDidMount() {
this.props.fetchReviews(this.props.business.id)
// .then (() => this.setState({reviews: this.props.reviews}))
this.setState({loading: false})
console.log(this.props)
}
render() {
const { business, reviews } = this.props;
if (!this.props.reviews) return null;
if (this.state.loading === true) {
return <p>Loading...</p>
}
return (
<div className="business-show">
<Link to={`/business/${business.id}`} className='link-business-index'>
<img className="business-index-photo" src={business.photo_urls[0]} alt=""/>
<p className="business-index-name">{business.name}</p>
<Star reviews={reviews}/>
<p className="business-index-city">{business.city}</p>
<p className="business-index-cost">Cost: {business.cost}</p>
<p className="business-index-hours">Hours: {business.open} - {business.close}</p>
</Link>
</div>
)
}
};
export default BusinessShowIndex;
container:
import { connect } from 'react-redux';
import {fetchReviews} from '../../actions/review_actions';
import { withRouter } from 'react-router-dom';
import BusinessShowIndex from './business_show_index';
const mapStateToProps = (state, ownProps) => ({
business: state.entities.businesses[ownProps.business.id],
currentUser: state.entities.users[state.session.id],
reviews: Object.values(state.entities.reviews)
})
const mapDispatchToProps = dispatch => ({
fetchReviews: (businessId) => dispatch(fetchReviews(businessId))
})
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(BusinessShowIndex));
let me know what else you need to see! thank you!
also any advice to clean code? taking any suggestions.
Inside componentDidMount Im calling the dispatched fetchReviews. but once mounted how does the fetched reviews get set in props?
You can get using this.props.review
Check your mapStateToProps function. You get the entire state there and it returns whatsever part of it you want to return.
I am building an app with react / redux for managing Collection of Electronic equipment (=donations). I have several routes that their functionality - is similiar - fetching entity (it could be volunteer, donor etc) data and show it in a table.
the volunteer route:
import React, {Component} from 'react';
import { connect } from 'react-redux';
import { requestVolunteerData } from '../actions/entitiesAction';
import { volenteerColumns as columns } from '../utils/entitiesColumns/volenteerColumns';
import '../container/App.css';
import Table from '../components/Table/Table';
import Loading from '../components/Loading/Loading';
const mapStateToProps = state => {
return {
entities: state.requestEntitiesReducer.entities,
isPending: state.requestEntitiesReducer.isPending,
error: state.requestEntitiesReducer.error
}
}
const mapDispatchToProps = dispatch => {
return {
onRequestEntities: () => dispatch(requestVolunteerData())
}
}
class Volenteer extends Component{
componentDidMount () {
this.props.onRequestEntities();
}
render () {
const { entities, isPending} = this.props;
return isPending ?
<Loading />
:
(
<div className='tc'>
<h1 className='f2'>רשימת מתנדבים</h1>
<Table data={ entities } columns={ columns } />
</div>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Volenteer);
and a consumer route look like this:
import React, {Component} from 'react';
import { connect } from 'react-redux';
import { requestConsumerData } from '../actions/entitiesAction';
import { consumerColumns as columns } from '../utils/entitiesColumns/consumerColumns';
import '../container/App.css';
import Table from '../components/Table/Table';
import Loading from '../components/Loading/Loading';
const mapStateToProps = state => {
return {
entities: state.requestEntitiesReducer.entities,
isPending: state.requestEntitiesReducer.isPending,
error: state.requestEntitiesReducer.error
}
}
const mapDispatchToProps = dispatch => {
return {
onRequestEntities: () => dispatch(requestConsumerData())
}
}
class Consumer extends Component{
componentDidMount () {
this.props.onRequestEntities();
}
render () {
const { entities, isPending} = this.props;
return isPending ?
<Loading />
:
(
<div className='tc'>
<h1 className='f2'>רשימת נזקקים</h1>
<Table data={ entities } columns={ columns }/>
</div>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Consumer);
As you can see, they both have the same logic and the differences are:
the action
the Entity name for the h1 tag
the columns object
the data of course
so I tried to implement an HOC which look like this:
import React, {Component} from 'react';
import { connect } from 'react-redux';
import '../container/App.css';
import Table from '../Table/Table';
import Loading from '../Loading/Loading';
export default function WithEntity (EntityComponent, action, columns, name) {
const mapStateToProps = state => {
return {
isPending: state.requestEntitiesReducer.isPending,
entities: state.requestEntitiesReducer.entities,
error: state.requestEntitiesReducer.error
}
}
const mapDispatchToProps = dispatch => {
return {
onRequestEntities: () => dispatch(action)
}
}
class extends Component {
componentDidMount () {
this.props.onRequestEntities();
}
render() {
return (
<EntityComponent {...this.props} />
)
}
}
return connect(mapStateToProps, mapDispatchToProps)(EntityComponent);
}
and the volunteer should look like:
const volunteerHoc = WithEntity (volunteer, action, columns, name);
const consumerHoc = WithEntity (consumer, action, columns, name)
but I did not understand how to inject the Loading and Table components, and wht the name of the class inside the HOC should be-
should I use another HOC - something like WithLoader that receive the data from the first one and render the Loading and Table components with the proper data? just to mention that connect is HOC itself so I need to return the EntityComponent to the redux store :
return connect(mapStateToProps, mapDispatchToProps)(EntityComponent);
I Would appreciate any help
OK, I made it, the HOC takes a basic component, Expands the functionality (by adding methods and managing state for ex) and return a new (henanced) comp with this props.
lets create a simple volunteer comp:
import React, {Component} from 'react';
import { requestVolunteerData } from '../actions/entitiesAction';
import { volenteerColumns as columns } from '../utils/entitiesColumns/volenteerColumns';
import '../container/App.css';
import WithEntity from '../components/HOC/WithEntity.jsx';
import Table from '../components/Table/Table';
import Loading from '../components/Loading/Loading';
class Volenteer extends Component {
render() {
const { entities, isPending} = this.props;
return isPending ?
<Loading />
:
(
<div className='tc'>
<h1 className='f2'>רשימת מתנדבים</h1>
<Table data={ entities } columns={ columns } />
</div>
);
}
}
const VolenteerHOC = WithEntity(Volenteer, requestVolunteerData() );
export default VolenteerHOC;
now lets create the HOC WithEntity that managing the state and return the new cmop to redux state by connect:
import React, {Component} from 'react';
import { connect } from 'react-redux';
const WithEntity = (EntityComponent, action) => {
const mapStateToProps = state => {
return {
isPending: state.requestEntitiesReducer.isPending,
entities: state.requestEntitiesReducer.entities,
error: state.requestEntitiesReducer.error
}
}
const mapDispatchToProps = dispatch => {
return {
onRequestEntities: () => dispatch(action)
}
}
class NewCmoponent extends Component {
componentDidMount () {
this.props.onRequestEntities();
}
render() {
const { entities, isPending} = this.props;
return (
<EntityComponent {...this.props} />
)
}
}
return connect(mapStateToProps, mapDispatchToProps)(NewCmoponent );
}
export default WithEntity;
Now same route can be simply generated via this HOC.
check out this video:
https://www.youtube.com/watch?v=rsBQj6X7UK8
I'm currently working on a react app exercise based around creating Spotify playlists. Here is the primary code-base:
App.js
import React from 'react';
import './App.css';
import SearchBar from'../SearchBar/SearchBar';
import SearchResults from '../SearchResults/SearchResults';
import Playlist from '../Playlist/Playlist';
const track = {
name: "Hello",
artist: "Again",
album: "Friend of a friend",
id: 0
};
const tracks = [track, track, track];
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
searchResults: tracks,
playlistName: "DEFAULT",
playlistTracks: tracks
};
this.addTrack = this.addTrack.bind(this);
this.removeTrack = this.removeTrack.bind(this);
}
addTrack(track) {
this.state.playlistTracks.map(id => {
if(track.id === id)
return;
});
this.setState((state, track) => ({
playlistTracks: state.playlistTracks.push(track)
}));
}
removeTrack(track) {
this.state.playlistTracks.map(id => {
if(track.id === id)
{
this.setState((state, track) => ({
playlistTracks: state.playlistTracks.remove(track)
}));
}
});
}
render(){
return (
<div>
<h1>Ja<span className="highlight">mmm</span>ing</h1>
<div className="App">
<SearchBar />
<div className="App-playlist">
<SearchResults searchResults={this.state.searchResults} onAdd= {this.addTrack}/>
<Playlist name= {this.state.playlistName} tracks= {this.state.playlistTracks} onRemove= {this.removeTrack}/>
</div>
</div>
</div>
);
}
}
export default App;
Playlist.js
import React from 'react';
import './Playlist.css';
import TrackList from '../TrackList/TrackList';
function Playlist(props) {
return (
<div className="Playlist">
<input value="New Playlist"/>
<button className="Playlist-save">SAVE TO SPOTIFY</button>
<TrackList tracks= {props.tracks} onRemove= {props.onRemove} isRemoval= {true}/>
</div>
);
}
export default Playlist;
import React from 'react';
import './SearchBar.css';
function SearchBar () {
return (
<div className="SearchBar">
<input placeholder="Enter A Song, Album, or Artist" />
<button className="SearchButton">SEARCH</button>
</div>
);
}
export default SearchBar;
SearchBar.js
import React from 'react';
import './SearchBar.css';
function SearchBar () {
return (
<div className="SearchBar">
<input placeholder="Enter A Song, Album, or Artist" />
<button className="SearchButton">SEARCH</button>
</div>
);
}
export default SearchBar;
SearchResults.js
import React from 'react';
import './SearchResults.css';
import TrackList from '../TrackList/TrackList';
function SearchResults (props) {
return (
<div className="SearchResults">
<h2>Results</h2>
<TrackList tracks={props.searchResults} onAdd= {props.onAdd} isRemoval= {false}/>
</div>
);
}
export default SearchResults;
Track.js
import React from 'react';
import './Track.css';
class Track extends React.Component {
constructor(props) {
super(props);
this.addTrack = this.addTrack.bind(this);
this.removeTrack = this.addTrack.bind(this);
}
addTrack() {
this.props.onAdd(this.props.track);
}
removeTrack() {
this.props.onRemove(this.props.track);
}
render() {
return (
<div className="Track">
<div className="Track-information">
<h3>{ this.props.track.name }</h3>
<p>{ this.props.track.artist } | { this.props.track.album }</p>
<div onClick= {this.addTrack}>+</div>
<div onClick= {this.removeTrack}>-</div>
</div>
</div>
);
}
}
export default Track;
TrackList.js
import React from 'react';
import './TrackList.css';
import Track from '../Track/Track';
function TracklList (props) {
return (
<div className="TrackList">
{
props.tracks.map(track => {
return <Track
track={track}
key={track.id}
onAdd= {props.onAdd}
onRemoval= {props.onRemoval}
isRemove= {props.isRemove}
/>;
})
}
</div>
);
}
export default TracklList;
It's a very baseline application at the moment but I'm trying to test a certain functionality so far. I am trying to test the process of adding a song from the Results section into the Playlist. However, when I click the plus icon on one of the songs, I get the following bug:
The bug only pops up after I click the plus icon so my initial assumptions is that I am changing the state object from an array to a list. however, I don't kow how that is the case. Anyway, I could definitely use a second opinion so far!
Array.push mutate the calling array and returns a number indicate the length of the new array.
In your addTrack method, your old playlistTracks state was mutated and new state was set to be a number instead of the new array.
Use the spread syntax to add new item to your array in an immutable way.
Also setState accept a new state, or a function that received old state and return new state, track should be received from the addTrack method
P/S: the .map above the setState seems like it won't work as intended.
addTrack(track) {
/*
* NOTE: the code below doesn't affect anything since `map`
* will be applied on each item and does not stop when you `return`
* also, it seems like `playlistTracks` is an array of object, but was
* used as an array of string here
*/
this.state.playlistTracks.map(id => {
if (track.id === id)
return;
});
this.setState((state/* ,track -- I think this should be removed */) => ({
// old code: playlistTracks: state.playlistTracks.push(track)
playlistTracks: [...state.playlistTracks, track]
}));
}
In my stateless component DebtType I am triggering 'handleChangeDebtType'
on the onChange event:
const DebtType = (options, handleChangeDebtType) => {
console.log(options);
return (
<select onChange={handleChangeDebtType}>
{options.options.map(option => {
return <option>{option.label}</option>;
})}
</select>
);
};
export default DebtType;
This DebtType component is called in MyContainer:
import React, { Component } from "react";
import DebtType from "./DebtType";
import mockOptions from "./mockData.json";
import ClearDebtType from "./ClearDebt";
import { reduxForm } from "redux-form";
import { connect } from "react-redux";
class MyContainer extends Component {
handleChangeDebtType= () => {
//save selected debttype to store
console.log("handleChangeDebtType");
}
render() {
return (
<div>
<DebtType
options={mockOptions.DEBT_TYPE}
handleChangeDebtType={this.handledChangeDebtType}
/>
<ClearDebtType options={mockOptions.CLEARDEBT_TYPE} />
</div>
);
}
}
const mapStateToProps = state => ({
//selectedDebtType:
});
MyContainer = connect(
mapStateToProps,
undefined
)(MyContainer);
export default reduxForm({
form: "simple" // a unique identifier for this form
})(MyContainer);
//export default ;
How can I trigger the 'handleChangeDebtType' event? Currently it is not firing.
updated the handleChangeDebtType function, minor typo in ur handleChangeDebtType function name
import React, { Component } from "react";
import DebtType from "./DebtType";
import mockOptions from "./mockData.json";
import ClearDebtType from "./ClearDebt";
import { reduxForm } from "redux-form";
import { connect } from "react-redux";
class MyContainer extends Component {
handleChangeDebtType = () => {
//save selected debttype to store
console.log("handleChangeDebtType");
};
render() {
return (
<div>
<DebtType
options={mockOptions.DEBT_TYPE}
handleChangeDebtType={() => {
this.handleChangeDebtType();
}}
/>
<ClearDebtType options={mockOptions.CLEARDEBT_TYPE} />
</div>
);
}
}
const mapStateToProps = state => ({
//selectedDebtType:
});
MyContainer = connect(
mapStateToProps,
undefined
)(MyContainer);
export default reduxForm({
form: "simple" // a unique identifier for this form
})(MyContainer);
//export default ;
de-structured the component props
import React from "react";
const DebtType = ({options, handleChangeDebtType}) => {
console.log(options);
return (
<select onChange={handleChangeDebtType}>
{options.map(option => {
return <option key={option.label}>{option.label}</option>;
})}
</select>
);
};
export default DebtType;
All you forgot to do was add de-structured props to the function component DebtType , in your example the handleChangeDebtType was not being picked up as a function that's why it wasn't firing. Also don't forget to add the key when looping though array.
Link to fixed codesandbox : https://codesandbox.io/s/kkxz980qw5
import React from "react";
const DebtType = ({ options, handleChangeDebtType }) => {
console.log(options);
return (
<select onChange={handleChangeDebtType}>
{options.map((option, index) => {
return <option key={index}>{option.label}</option>;
})}
</select>
);
};
export default DebtType;
I've set up my Redux to capture a user selection from a webshop (item, size, price) and send it to another Cart component. This is working perfectly, but I want to capture an image of the item and send it to Cart. Within each product page where you can add an item to the cart there is an image that I also would like to send with the user selection. This is an example of the product page component:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { addCart } from '../../actions';
import SeltzShirt from './seltzshirt.jpg';
import Slideone from './slideSeltzOne';
import Slidetwo from './slideSeltzTwo';
import RightArrow from './rightarrow';
import LeftArrow from './leftarrow';
export class ProductPage3 extends Component {
constructor(props) {
super(props);
this.state = {
slideCount: 1,
value: 'medium', cartData: {}
}
this.nextSlide = this.nextSlide.bind(this);
this.previousSlide = this.previousSlide.bind(this);
this.handleClick = this.handleClick.bind(this);
this.change = this.change.bind(this);
}
handleClick() {
let cart = {price:25,item:this.description.innerHTML,size:this.state.value};
this.props.onCartAdd(cart);
console.log(cart);
this.itemSelection(cart);
}
...
componentDidMount () {
window.scrollTo(0, 0)
}
render() {
return (
<div className= "ProductPage" id="ProductPage">
<div id='slider'>
{this.state.slideCount === 1 ? <Slideone /> : null}
{this.state.slideCount === 2 ? <Slidetwo /> : null}
<RightArrow nextSlide={this.nextSlide} />
<LeftArrow previousSlide={this.previousSlide} />
</div>
<div id='InfoSquare'>
<div id='wrapper'>
<div id='item' ref={i=>this.description=i}>LOGO TEE</div>
<div id='description'>Black tee 100% cotton with red silkscreened logo on front and back.</div>
<select id="size2" onChange={this.change} value={this.state.value}>
<option value="medium">Medium</option>
<option value="large">Large</option>
<option value="x-large">X-large</option>
</select>
<button onClick={this.handleClick} className="addit">ADD TO CART</button>
</div>
</div>
</div>
);
}
nextSlide() {
this.setState({ slideCount: this.state.slideCount + 1 })
}
previousSlide() {
this.setState({ slideCount: this.state.slideCount - 1 })
}
}
const mapDispatchToProps = (dispatch) => {
return {
onCartAdd: (cart) => {
dispatch(addCart(cart));
},
}
}
function mapStateToProps(state) {
return {
cart: state.cart
};
}
export default connect(mapStateToProps,mapDispatchToProps)(ProductPage3);
This is my Cart component:
import React, { Component } from 'react';
import {addCart} from './Shop';
import { removeCart } from '../../actions';
import { connect } from 'react-redux';
export class Cart extends Component {
constructor(props) {
super(props);
this.state = {items: this.props.cart,cart: [],total: 0};
}
...
render() {
return(
<div className= "Webcart" id="Webcart">
<div id='WebcartWrapper'>
<ul id='webCartList'>
{this.state.items.map((item, index) => {
return <li className='cartItems' key={'cartItems_'+index}>
<h4>{item.item}</h4>
<p>Size: {item.size}</p>
<p>Price: {item.price}</p>
<button onClick={() => this.handleClick(item)}>Remove</button>
</li>
})}
</ul>
<div>Total: ${this.countTotal()}</div>
</div>
</div>
);
}
}
const mapDispatchToProps = (dispatch) => {
return {
onCartAdd: (cart) => {
dispatch(addCart(cart));
},
onCartRemove: (item) => {
dispatch(removeCart(item));
},
}
}
function mapStateToProps(state) {
return { cart: state.cart };
}
export default connect(mapStateToProps, mapDispatchToProps)(Cart);
In Cart I'm rendering the item selection data for each object added to the cart. Here is where I want to display the item image also.
Since I have a image slider set up, an example of one of the slides would be:
import React, { Component } from 'react';
import take1 from './DETAIL.png';
const SlideNocHOne= (props) => {
return <img src= {take1} id="slide"></img>
}
export default SlideNocHOne;
Let's say I want this DETAIL.png image on the Cart, how could I transfer it with the user selection using Redux?
These are my Redux components:
import { createStore, applyMiddleware, compose } from 'redux';
import { persistStore, autoRehydrate } from 'redux-persist';
import reducer from './reducers';
import thunkMiddleware from 'redux-thunk';
import {createLogger} from 'redux-logger';
const store = createStore(
reducer,
undefined,
compose(
applyMiddleware(createLogger(), thunkMiddleware),
autoRehydrate()
)
);
persistStore(store, {whitelist: ['cart']});
export default store;
import {ADD_CART} from './actions';
import {REMOVE_CART} from './actions';
import { REHYDRATE } from 'redux-persist/constants';
export default Reducer;
var initialState = {
cart:{},
data: [],
url: "/api/comments",
pollInterval: 2000
};
function Reducer(state = initialState, action){
switch(action.type){
case REHYDRATE:
if (action.payload && action.payload.cart) {
return { ...state, ...action.payload.cart };
}
return state;
case ADD_CART:
return {
...state,
cart: [...state.cart, action.payload]
}
case REMOVE_CART:
return {
...state,
cart: state.cart.filter((item) => action.payload !== item)
}
default:
return state;
};
}
export const ADD_CART = 'ADD_CART';
export const REMOVE_CART = 'REMOVE_CART';
export function addCart(item){
return {
type: ADD_CART,
payload: item
}
};
export function removeCart(item){
return{
type:REMOVE_CART,
payload: item
}
};
How can I use my Redux setup to transfer the image of a user selection to Cart?
If the path's of your components are relatively stable and you have a single location for the images, you can simply have a function that takes a component's displayName (in your example, Cart, etc.) and returns the relative path the image dir.
If you have that, you can just save a key/value collection in the reducer for what images each component should have, like:
{
CartComponent: ['DETAIL.png', 'DETAIL_2.png']
...
}
When rending just use the mapper function which will provide you a relative path and that's it. Something like (or you can just map out that array):
const relativeImagePath = getRelativeImageDirPathByCompName('CartComponent') + this.props.images.CartComponent[0];
Use require to fetch the image in the template like:
<img src={require(relativeImagePath)} alt="Something"/>