I have created an UPDATE_ITEM type but how to code it in here I don't have the idea since I want to update it by its ID. Also I want to dipatch this action with the reducer itemReducer.js which I have given in the code below. Can someone please help me with the code?//itemAction.js Action. The get, delete and add routes is working but this put method is giving me headache.
import axios from 'axios';
import { GET_ITEMS, ADD_ITEM, DELETE_ITEM, UPDATE_ITEM, ITEMS_LOADING } from'./types';
export const getItems = () => dispatch => {
dispatch(setItemsLoading());
axios.get('/api/items').then(res =>
dispatch({
type: GET_ITEMS,
payload: res.data
})
);
};
export const addItem = item => dispatch => {
axios.post('/api/items', item).then(res =>
dispatch({
payload: res.data
})
);
};
//UPDATE_ITEM Action Here
export const deleteItem = id => dispatch => {
axios.delete(`/api/items/${id}`).then(res =>
dispatch({
type: DELETE_ITEM,
payload: id
})
);
};
export const setItemsLoading = () => {
return {
type: ITEMS_LOADING
};
};
This is the itemReducer which I also need help
import { GET_ITEMS, DELETE_ITEM, UPDATE_ITEM, ADD_ITEM, ITEMS_LOADING
} from '../actions/types';
const initialState = {
items: [],
loading: false
};
export default function(state = initialState, action) {
switch (action.type) {
case GET_ITEMS:
return {
...state,
items: action.payload,
loading: false
};
case DELETE_ITEM:
return {
...state,
items: state.items.filter(item => item._id !== action.payload)
};
//UPDATE_ITEM Reducer here
case ADD_ITEM:
return {
...state,
items: [action.payload, ...state.items]
};
case ITEMS_LOADING:
return {
...state,
loading: true
};
default:
return state;
}
}
I guess your update looks like the add:
//UPDATE_ITEM Action
export const updateItem = item => dispatch => {
axios.put('/api/items', item).then(res =>
dispatch({
type:'UPDATE_ITEM',
payload: res.data
})
);
};
In your reducer you can use map
case UPDATE_ITEM:
return {
...state,
items: state.items.map(
item =>
item._id === action.payload.id
//return action payload (modified item) instead of
// original item when item id is updated item id
? action.payload
: item//ids not the same, return original item
)
};
import React, { Component } from 'react';
import { Container, ListGroup, ListGroupItem, Button } from 'reactstrap';
import { CSSTransition, TransitionGroup } from 'react-transition-group';
import { connect } from 'react-redux';
import { getItems, deleteItem, updateItem } from '../actions/itemActions';
import PropTypes from 'prop-types';
class ShoppingList extends Component {
componentDidMount() {
this.props.getItems();
}
onDeleteClick = id => {
this.props.deleteItem(id);
};
render() {
const { items } = this.props.item;
return (
<Container>
<ListGroup>
<TransitionGroup className="shopping-list">
{items.map(({ _id, name, body }) => (
<CSSTransition key={_id} timeout={500} classNames="fade">
<ListGroupItem>
<Button
className="remove-btn"
color="danger"
size="sm"
onClick={this.onDeleteClick.bind(this, _id)}
>
DELETE
</Button>
{/*An update button will be called here*/}
{/*<Button
className="update-btn"
color="success"
size="sm"
>
Update
</Button>*/}
<div></div>
<table className="rows">
<thead>
<tr>
<td>Name</td>
<td>Body</td>
</tr>
</thead>
<tbody>
<tr>
<td>{ name }</td>
<td>{ body }</td>
</tr>
</tbody>
</table>
</ListGroupItem>
</CSSTransition>
))}
</TransitionGroup>
</ListGroup>
</Container>
);
}
}
ShoppingList.propTypes = {
getItems: PropTypes.func.isRequired,
item: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
item: state.item
});
export default connect(
mapStateToProps,
{ getItems, deleteItem }
)(ShoppingList);
Related
delete product from database and table (mern project)
this is my code. but the product is not being deleted and showing this error - xhr.js:210 DELETE http://localhost:3000/api/v1/admin/product/24e74a20a5e5e8574e231a0 404 (Not Found)
I'm trying but I can't solve the problem. Please give me some advice.
productRoute.js
router.route('/admin/product/:id')
.put(isAuthenticatedUser,authorizeRoles("admin"), updateProduct)
.post(isAuthenticatedUser,authorizeRoles("admin"), deleteProduct)
productController.js
exports.deleteProduct = catchAsyncError(async(req,res,next) => {
const product = await Product.findById(req.params.id)
if(!product){
return next(new ErrorHandler("Product not found",404));
}
await product.remove();
res.status(200).json({
success:true,
message:"product deleted successfully"
})
})
productConstant.js
export const DELETE_PRODUCT_REQUEST = "DELETE_PRODUCT_REQUEST";
export const DELETE_PRODUCT_SUCCESS = "DELETE_PRODUCT_SUCCESS";
export const DELETE_PRODUCT_RESET = "DELETE_PRODUCT_RESET";
export const DELETE_PRODUCT_FAIL = "DELETE_PRODUCT_FAIL";
export const CLEAR_ERROR ="CLEAR_ERROR";
productAction.js
export const deleteProduct = (id) => async (dispatch) => {
try {
dispatch({ type: DELETE_PRODUCT_REQUEST });
const { data } = await axios.delete(`/api/v1/admin/product/${id}`);
dispatch({
type: DELETE_PRODUCT_SUCCESS,
payload: data.success,
});
} catch (error) {
dispatch({
type: DELETE_PRODUCT_FAIL,
payload: error.response.data.message,
});
}
};
productReducer.js
export const productsReducer = (state ={products: []},action) => {
switch(action.type){
case ALL_PRODUCTS_REQUEST:
case ADMIN_PRODUCT_REQUEST:
return{
loading:true,
products:[]
}
case ALL_PRODUCTS_SUCCESS:
return{
loading:false,
products:action.payload.products,
productCount:action.payload.productCount
}
case ADMIN_PRODUCT_SUCCESS:
return{
loading:false,
products:action.payload,
}
case ALL_PRODUCTS_FAIL:
case ADMIN_PRODUCT_FAIL:
return{
loading:false,
error:action.payload
}
case CLEAR_ERROR:
return{
...state,
error:null
}
default:
return state;
}
};
export const productReducer = (state = {}, action) => {
switch (action.type) {
case DELETE_PRODUCT_REQUEST:
return {
...state,
loading: true,
};
case DELETE_PRODUCT_SUCCESS:
return {
...state,
loading: false,
isDeleted: action.payload,
};
case DELETE_PRODUCT_FAIL:
return {
...state,
loading: false,
error: action.payload,
};
case DELETE_PRODUCT_RESET:
return {
...state,
isDeleted: false,
};
case CLEAR_ERROR:
return {
...state,
error: null,
};
default:
return state;
}
};
store
const reducer = combineReducers({
products:productsReducer,
product: productReducer,
})
ProductList.js
import React, { Fragment, useEffect } from 'react'
import { useSelector, useDispatch } from "react-redux";
import SideBar from "./Sidebar";
import {
clearErrors,
getAdminProduct,
deleteProduct
} from "../../Actions/productAction";
import { Link,} from "react-router-dom";
import './ProductList.css'
import { DELETE_PRODUCT_RESET } from "../../Constants/productConstant";
import { useNavigate } from 'react-router';
const ProductList = () => {
const dispatch = useDispatch();
const navigate = useNavigate();
const { error, products } = useSelector((state) => state.products);
const { error: deleteError, isDeleted } = useSelector(
(state) => state.product
);
useEffect(() => {
if (error) {
alert(error);
dispatch(clearErrors());
}
if (deleteError) {
alert(deleteError);
dispatch(clearErrors());
}
if (isDeleted) {
alert("Product Deleted Successfully");
navigate("/admin/dashboard");
dispatch({ type: DELETE_PRODUCT_RESET });
}
dispatch(getAdminProduct());
}, [dispatch,error,deleteError,isDeleted]);
return (
<Fragment>
<div className='adminproductlistedit'>
<div className='table_overflow'>
<table id='table'>
<thead> {/* The Head of The Table */}
<tr>
<th className='editTable editProductId'>Product ID</th>
<th className='editTable editName'>Name</th>
<th className='editTable editStock'>Stock</th>
<th className='editTable editCategory'>Category</th>
<th className='editTable editPrice'>Price</th>
<th className='editTable adminActions'>Actions</th>
</tr>
</thead>{/* End of The Head */}
<tbody> {/* The Body of The Table */}
{products &&
products.map((item) => (
<tr className='tr'>
<td>{item._id}</td>
<td>{item.name}</td>
<td>{item.stock}</td>
<td>{item.category}</td>
<td>{item.price}</td>
<td className='actiondiv'>
<button><Link to={`/admin/product/${item._id}`}>
Edit <i className=" editicon fa-solid fa-pencil" />
</Link></button>
<button onClick={() => {
dispatch(deleteProduct(item._id))}}
>Delete <i className="deleteicon fa-solid fa-trash-can" /></button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</Fragment>
)
}
export default ProductList
You should declare your DELETE route as a delete request:
router
.route('/admin/product/:id')
.put(isAuthenticatedUser, authorizeRoles('admin'), updateProduct)
.delete(isAuthenticatedUser, authorizeRoles('admin'), deleteProduct);
Also, you can simplify your controller by using findByIdAndDelete:
exports.deleteProduct = catchAsyncError(async(req,res,next) => {
await Product.findByIdAndDelete(req.params.id)
res.status(200).json({
success:true,
message:"product deleted successfully"
})
})
I am building a basket ecommerce app and my add to cart function is working fine, however when I use my remove item function it does not work, in fact it just adds the same item to the cart again but then the total displays as NaN.
I am just using .filter to return a new array without the items that I want removed by using its id, so not sure how this is happening.
If you want to replicate what I am talking about in code sandbox just click the add to cart button - then click top right basket icon to go to basket page - then click the minus button to remove the item.
code sandbox here
code below:
CartReducer.js
import {ADD_TO_CART, REMOVE_ITEM} from '../Types'
export const CartReducer = (state, action) => {
switch (action.type) {
case ADD_TO_CART: {
return {
...state,
cartItems: [...state.cartItems, action.payload],
}
}
case REMOVE_ITEM: {
return {
...state,
cartItems: state.cartItems.filter((item) => item.id !== action.payload.id),
}
}
default:
return state
}
}
CartState.js
import { useReducer } from 'react'
import { CartContext } from './CartContext'
import {CartReducer} from './CartReducer'
import { SHOW_HIDE_CART, ADD_TO_CART, REMOVE_ITEM } from '../Types'
import {products} from '../../pages/ProductDetailsPage'
export const CartState = ({children}) => {
const initialState ={
// showCart: false,
products: products,
cartItems: [],
};
const [state, dispatch] = useReducer(CartReducer, initialState);
const addToCart = (item) => {
dispatch({type: ADD_TO_CART, payload: item})
};
const removeItem = (id) => {
dispatch({ type: REMOVE_ITEM, payload: id });
};
return (
<CartContext.Provider
value={{
products: state.products,
cartItems: state.cartItems,
addToCart,
removeItem,
}}>
{children}
</CartContext.Provider>
)
};
BasketItem.js
import React, { useContext } from 'react'
import image from '../assets/image.png'
// import { QuantityButtonDiv } from '../components/QuantityButtonDiv'
import plusButtonImage from '../assets/vector+.png'
import subtractButtonImage from '../assets/vector.png'
import { CartContext } from '../context/cart/CartContext'
export const BasketItem = ({item}) => {
const { cartItems, removeItem } = useContext(CartContext);
return (
<div className="basket-item">
<div className="title-div">
<span>
{item.title}
</span>
</div>
<div className="image-div">
<img style={{height: "100%", width: "100%"}} src={image}/>
</div>
<div className="price-div">
<span>
£{item.price}
</span>
</div>
<div className="basket-quantity-div">
<button onClick={() => removeItem(item.id)} className="subtract-btn">
<img src={subtractButtonImage}/>
</button>
<span className="quantity-value">
{cartItems.length}
</span>
<button className="add-btn">
<img src={plusButtonImage}/>
</button>
</div>
<div className="total-div">
£{cartItems.reduce((amount, item) => item.price + amount, 0)}
</div>
</div>
)
}
Are you double checked removeItem function?
In the dispatch you are sending { payload: id } and then the reducer get the value from payload.id. If you want to manage the reducer in this way you have to send in the payload an object { id: id } or shorthanded { id }
This is just a sample code I am trying to control my controlled inputs using Redux, I add the Redux to my React project and add my reducer and action but everything works well except updating my component in one of my actions.
the following code is my Reducer:
import actionTypes from "./actions";
const uniqid = require("uniqid");
const firstID = uniqid();
const initialState = {
cons: [
{
value: "",
id: firstID,
added: false
}
],
pros: [
{
value: "",
id: firstID,
added: false
}
],
num: 0
};
const reducer = (state = initialState, action) => {
const newState = { ...state };
switch (action.type) {
case actionTypes.HANDLEINPUTCHANGE:
// const newState = state;
const changingItem = newState[action.case].find(item => {
return item.id === action.id;
});
const changingItemIndex = newState[action.case].findIndex(item => {
return item.id === action.id;
});
changingItem.value = action.event;
if (
changingItemIndex === newState[action.case].length - 1 &&
!changingItem.added
) {
alert(123);
const newItem = {
id: uniqid(),
value: "",
added: false
};
newState[action.case].push(newItem);
changingItem.added = true;
console.log(newState);
}
newState[action.case][changingItemIndex] = changingItem;
return newState;
case actionTypes.CLICK:
newState.num += 1;
return {
...newState
};
default:
return state;
}
};
export default reducer;
and the following code is my component, unfortunately, the HANDLEINPUTCHANGE action type did not update my component:
import React, { Component } from "react";
import FormElement from "../../base/components/formElement/FormElement";
import actionTypes from "../../base/store/actions";
import { connect } from "react-redux";
import "./style.scss";
class FormGenerator extends Component {
render() {
console.log(this.props);
return (
<ul className="row formGeneratorContainer fdiColumn">
<li onClick={this.props.click}>{this.props.num}</li>
{this.props[this.props.case].map((item, index) => {
return (
<li className="row formGeneratorItem" key={index}>
<div className="bullet d_flex jcCenter aiCenter">1</div>
{/* <FormElement onChange={(e,index,type,)}/> */}
<input
name={item.id}
type="text"
onChange={event =>
this.props.onFieldValueChange(
event.target.value,
index,
this.props.case,
item.id
)
}
/>
</li>
);
})}
</ul>
);
}
}
const mapStateToProps = state => {
return {
cons: state.cons,
pros: state.pros,
num: state.num
};
};
const mapDispachToProps = dispatch => {
return {
onFieldValueChange: (event, index, c, id) =>
dispatch({
event: event,
index: index,
case: c,
id: id,
type: actionTypes.HANDLEINPUTCHANGE
}),
click: () => dispatch({ type: actionTypes.CLICK })
};
};
export default connect(
mapStateToProps,
mapDispachToProps
)(FormGenerator);
You need to set value of your controlled component:
<input
name={item.id}
type="text"
value={item.value}
onChange={event =>
this.props.onFieldValueChange(
event.target.value,
index,
this.props.case,
item.id
)
}
/>
Other problems are in your reducer, you are mutating the redux state with these lines:
newState[action.case].push(newItem);
// ...
newState[action.case][changingItemIndex] = changingItem;
Look at these sections in the redux documentation:
Inserting and Removing Items in Arrays
Updating an Item in an Array
So I'm just practising my react redux skills. Im a beginner. I have created an action, reducer and several components. I'm basically making a todo app. I am fetching the data from an API which I have successfully done but the problem is arising when I'm trying to loop through the data and have it surrounded with <li> tags. I am getting Cannot read property 'map' of undefined which i dont understand why because in the console i can clearly see the array.
Action:
export function getLists(){
return function (dispatch) {
return fetch ("https://reqres.in/api/users?page=1")
.then( response => response.json())
.then (json => {console.log('sdsd'); console.log(json);
dispatch({ type: "ADD_ITEMS", payload: { json, loading: false} });
});
}
}
Reducer:
const initialState = {
todothings: [],
loading: true
};
function rootReducer (state = initialState, action) {
if( action.type === "ADD_ITEMS"){
console.dir("In the ADD_ITEMS reducer" + action.payload);
return Object.assign({}, state, {
todothings: state.todothings.concat(action.payload.json),
loading: action.payload.loading,
});
} else if ( action.type === "DELETE_ITEM") {
} else {
return state;
}
}
export default rootReducer;
ToDo Components:
import React, { Component } from 'react';
import { getLists } from '../actions/index';
import { connect } from 'react-redux';
import TodoItems from './TodoItems';
class TodosComponent extends Component {
componentDidMount(){
console.log('in the Todos comp -> componentDidMount()');
this.props.getList();
}
render(){
const {todothings , loading} = this.props;
if(!loading){
return(
<div>
<p>dfd</p>
{console.log(todothings)}
<TodoItems list={todothings}></TodoItems>
</div>
)
} else {
return (
<p>Fetching from upstream.</p>
)
}
}
}
function mapStateToProps(state){
return {
todothings: state.todothings,
loading: state.loading,
}
}
function mapDispatchToProps(dispatch){
return {
getList: () => dispatch(getLists())
};
}
const Todos = connect(mapStateToProps, mapDispatchToProps)(TodosComponent)
export default Todos;
TodoItem Component:
import React from 'react';
function TodoItems (props) {
return(
<div>
<ul>
{console.log('In the todoitems')}
{console.log(props)}
{props.list.map( element => (
<p>{element.data}</p>
))}
</ul>
</div>
);
}
export default TodoItems;
EDIT:
This is what I have so far now:
ToDoItems:
import React from 'react';
const TodoItems = ({ list = [] }) => {
if (list.length === 0) return null;
return (
<ul>
{list.map(item => (
<li key={item.id} {...item}>
<p>{item.first_name}</p>
</li>
))}
</ul>
);
};
export default TodoItems;
ToDo Component:
import React, { Component } from 'react';
import { getLists } from '../actions/index';
import { connect } from 'react-redux';
import TodoItems from './TodoItems';
class TodosComponent extends Component {
componentDidMount(){
console.log('in the Todos comp -> componentDidMount()');
this.props.getList();
}
render(){
const {todothings , loading} = this.props;
if(!loading){
return(
<div>
<p>dfd</p>
{console.log('in the todo comp')}
{console.log(todothings)}
<TodoItems list={todothings.data}></TodoItems>
</div>
)
} else {
return (
<p>Fetching from upstream.</p>
)
}
}
}
function mapStateToProps(state){
return {
todothings: state.todothings,
loading: state.loading,
}
}
function mapDispatchToProps(dispatch){
return {
getList: () => dispatch(getLists())
};
}
const Todos = connect(mapStateToProps, mapDispatchToProps)(TodosComponent)
export default Todos;
Reducer:
const initialState = {
todothings: [],
loading: true
};
function rootReducer (state = initialState, action) {
if( action.type === "ADD_ITEMS"){
console.dir("In the ADD_ITEMS reducer" + action.payload);
return Object.assign({}, state, {
todothings: state.todothings.concat(action.payload.json.data),
loading: action.payload.loading,
});
} else if ( action.type === "DELETE_ITEM") {
} else {
return state;
}
}
export default rootReducer;
Action:
export function getLists(){
return function (dispatch) {
return fetch ("https://reqres.in/api/users?page=1")
.then( response => response.json())
.then (json => {console.log('sdsd'); console.log(json);
dispatch({ type: "ADD_ITEMS", payload: { json, loading: false}
});
});
}
}
There are now no errors yet nothing is getting displayed:
(3) [{…}, {…}, {…}]
0: {id: 1, email: "george.bluth#reqres.in", first_name: "George", last_name: "Bluth", avatar: "https://s3.amazonaws.com/uifaces/faces/twitter/calebogden/128.jpg"}
1: {id: 2, email: "janet.weaver#reqres.in", first_name: "Janet", last_name: "Weaver", avatar: "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128.jpg"}
2: {id: 3, email: "emma.wong#reqres.in", first_name: "Emma", last_name: "Wong", avatar: "https://s3.amazonaws.com/uifaces/faces/twitter/olegpogodaev/128.jpg"}
length: 3
__proto__: Array(0)
Afternoon,
I think the data you want is from prop.list.data not props.list within <TodoItems />
In your component <TodDo /> try:
<TodoItems list={todothings.data}></TodoItems>
Then tidy up your stateless component <TodoItems /> (to cover an empty array):
const TodoItems = ({ list = [] }) => {
if (list.length === 0) return null;
return (
<ul>
{list.map(item => (
<li key={item.id} {...item}>
<ul>
{Object.keys(item).map((data, key) => (
<li {...{ key }}>{data}</li>
))}
</ul>
</li>
))}
</ul>
);
};
Note:
Your array has an object, with this shape:
{
id: 1,
email: "g.buth#reqres.in",
first_name: "George",
last_name: "Bluth"
}
What do you want to return in your <li>?
Update to loop through object.
I am new to to redux and react. Still doing simple tutorials. I managed to create 2 simple components; one that outputs on the screen (as a list) whatever is in the array in the redux store, and the other component contains a button and a textfield which basically adds to that array in the store.
I would like to add a feature that will enable me to delete a specific entry in the list depending on what the user clicked on. I am thinking of creating a <button> next to each <li> tag that gets rendered as it loops through the array, and these buttons will correspond to the respective list elements. But I'm not sure how to do that.
I've tried creating a button when each <li> tag gets created but I was getting an error on the console stating that each element in a list needs a unique ID. I then decided to create another array in my store called buttons which will contain a unique id as well as the id of the list but it got out of hand. I think I might be overcomplicating this. This is what I have at the moment:
Components:
List.jsx (responsible for outputting the list)
import React from 'react'
import { connect } from "react-redux";
const ListComp = ({ lists }) => (
<div>
<ul>
{console.log(lists)}
{lists.map( element => (
<li key={element.id}>
{element.titleToBeAddedToList}
</li>
))}
</ul>
</div>
)
const mapStateToProps = state => {
return {
lists: state.lists
};
}
const List = connect(mapStateToProps)(ListComp)
export default List;
SubmitButton.jsx (responsible for outputting the button and textfield)
import React from 'react'
import { connect } from "react-redux";
import uuidv1 from "uuid";
import { addList } from "../actions/index";
import { addButton } from "../actions/index"
function mapDispatchToProps(dispatch){
return {
addlist: article => dispatch(addList(article)),
addbutton: idOfButton => dispatch(addButton(idOfButton))
};
}
class Submit extends React.Component{
constructor(){
super();
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ [event.target.id]: event.target.value });
}
handleSubmit(event) {
event.preventDefault();
const {titleToBeAddedToList} = this.state;
const id = uuidv1();
const button_id = uuidv1();
//Dispatching the action:
this.props.addlist({ titleToBeAddedToList, id });
this.props.addbutton({id, button_id});
//Once we've dispatched an action, we want to clear the state:
this.setState({ titleToBeAddedToList: "" });
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label htmlFor="title">Title</label>
<input
type="text"
className="form-control"
id="titleToBeAddedToList"
onChange={this.handleChange}
/>
</div>
<button type="submit" className="btn btn-success btn-lg">
SAVE
</button>
</form>
);
}
}
const SubmitButton = connect(null, mapDispatchToProps)(Submit)
export default SubmitButton;
Reducers:
const initialState = {
lists: [],
buttons: []
};
function rootReducer (state = initialState, action) {
if(action.type === "ADD_LIST" ){
return Object.assign({}, state, {
lists: state.lists.concat(action.payload)
});
} else if(action.type === "ADD_BUTTON"){
return Object.assign({}, state, {
buttons: state.lists.concat(action.payload)
});
} else if(action.type === "DELETE_FROM_LIST"){
//.....//
}
return state;
}
export default rootReducer;
Action:
export function addList(payload) {
return { type: "ADD_LIST", payload }
};
export function addButton(payload){
return {type: "ADD_BUTTON", payload }
}
export function deleteList(payload){
return { type: "DELETE_FROM_LIST", payload }
}
Store:
import { createStore } from "redux";
import rootReducer from "../reducers/index";
const store = createStore(rootReducer);
export default store;
You can use Math.random() as an unique key identifier, if the button is click it will call action deleteItem with the ID, action is bound to reducer pass on the ID, you can then use the ID to indentify elements and remove it in the list.
import React from 'react'
import { connect } from "react-redux";
import { deleteItem } from './actions';
const ListComp = ({ lists }) => (
<div>
<ul>
{console.log(lists)}
{lists.map( element => (
<li key={Math.random()} key={element.id}>
{element.titleToBeAddedToList}
<button onClick={() => deleteItem(element.id)}>X</button>
</li>
))}
</ul>
</div>
)
const mapStateToProps = state => {
return {
lists: state.lists
};
}
const List = connect(mapStateToProps, {deleteItem})(ListComp) // Make it available to component as props
export default List;
Action:
export function deleteElement(id) {
return function(dispatch) {
return dispatch({type: "DELETE_FROM_LIST", payload: id})
}
}
Reducer:
case 'DELETE_FROM_LIST': {
const id = action.payload;
return {
...state,
list: state.list.filter(item => item.id !== id)
}
}
else if (action.type === "DELETE_FROM_LIST") {
return Object.assign({}, state, {
buttons: state.lists.filter(item => (item.id !==action.payload))
});
}
you can use filter() for delete.
This is a minimal working react-redux example containing all the pieces to delete an item from an array in redux store.
// reducer.js
const reducer = (state, action) => {
switch (action.type) {
case 'DELETE':
return state.filter(item => (
item.id !== action.payload.id
))
default: return state;
}
}
// Item.js
const Item = ({id, onClick, label}) => (
<li>
{label}
<button onClick={ () => onClick(id) }>
delete
</button>
</li>
)
// ListContainer.js
const mapStateToProps = state => ({ items: state })
const ListContainer = ReactRedux.connect(mapStateToProps)(class extends React.Component {
handleDelete = id => {
const { dispatch } = this.props;
dispatch({ type: 'DELETE', payload: { id } })
}
render() {
const { items } = this.props;
return items.map(({id, label}) => (
<Item
label={label}
id={id}
onClick={this.handleDelete}
/>
))
}
})
// Main.js
const initialState = [
{ id: 1, label: 'item 1' },
{ id: 2, label: 'item 2' },
{ id: 3, label: 'item 3' },
{ id: 4, label: 'item 4' }
]
const store = Redux.createStore(reducer, initialState);
class App extends React.Component {
render(){
return (
<ReactRedux.Provider store={store}>
<ListContainer />
</ReactRedux.Provider>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.1/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/6.0.1/react-redux.js"></script>
<div id="root"></div>