2017-10-15 12 views
0

처음에는 모든 book-item에 deleteItem 이벤트를 첨부하려고합니다. 책 아이템의 ID를 받아들이는 액션 'DELETE_BOOK'을 가지고 있습니다. 그런 다음 리듀서에서 삭제되도록 지정한 책 아이템없이 책리스트를 반환합니다. 항목이 삭제되지만 어떤 이유에서 새 목록 (삭제 후 5 개 항목)에 이전 목록 (6 개 항목)을 추가하고 이제 11 개 항목으로 끝납니다.React/Redux - 다시 렌더링하면 이전 목록 (6)이 새 목록 (5)에 추가되고 총 11 개 항목이있는 총 6 개 항목을 삭제합니다.

Entire project source code

//book-list.js  
"use strict"  
import React from 'react'; 
import {connect} from 'react-redux'; 
import {bindActionCreators} from 'redux'; 
import {getBooks, deleteBook} from '../../actions/booksActions'; 
import BookItem from './book-item'; 
import BookForm from './book-form'; 
import Cart from './cart'; 

class BookList extends React.Component { 

    constructor(props){ 
     super(props); 
     this.deleteBookItem = this.deleteBookItem.bind(this); 
    } 

    componentDidMount(){ 
     this.props.getBooks(); 
    } 

    deleteBookItem(_id){ 
     this.props.deleteBook(_id); 
    } 

    render(){   
     const bookList = this.props.books.map(function(book){ 
      return (
       <BookItem 
        key={book._id} 
        _id={book._id} 
        title={book.title} 
        description={book.description} 
        price={book.price} 
        deleteBookItem={this.deleteBookItem} 
       /> 
      ) 
     }, this); 

     return(
      <div> 
       <div className="page-header"> 
        <h1 className="text-center">The React BookStore</h1> 
       </div> 
       { this.props.msg && 
        <div className="alert alert-info text-center" 
        role="alert">{this.props.msg}</div> 
       }     
       <Cart />     
       <div className="row"> 
        <div className="col-xs-12 col-sm-8"> 
         <div className="row"> 
          {bookList} 
         </div> 
        </div> 
        <div className="col-xs-12 col-sm-4"> 
         <BookForm /> 
        </div> 
       </div>        
      </div> 
     ) 
    } 
} 

//just return the data from the store 
function mapStateToProps(state){ 
    return {   
     books: state.books.books, 
     msg: state.books.msg 
    } 
} 

function mapDispatchToProps(dispatch){ 
    return bindActionCreators({ 
     getBooks: getBooks, 
     deleteBook: deleteBook 
    } 
    , dispatch); 
} 
//connects component to the store 
export default connect(mapStateToProps, mapDispatchToProps)(BookList); 

---------------------------------------------------------------------------- 

//book-item.js 
import React from 'react'; 
import {connect} from 'react-redux'; 
import {bindActionCreators} from 'redux'; 
import {addToCart, updateCart} from '../../actions/cartActions'; 

class BookItem extends React.Component{ 

    constructor(props){ 
     super(props); 
     this.deleteBookItem = this.deleteBookItem.bind(this); 
    } 

    deleteBookItem(){ 
     const index = this.props._id; 
     this.props.deleteBookItem(index); 
    } 

    handleCart =() => { 
     const book = [...this.props.cart, { 
      _id: this.props._id, 
      title: this.props.title, 
      description: this.props.description, 
      price: this.props.price, 
      qty: 1 
     }]; 
     if(this.props.cart.length > 0){ 
      let _id = this.props._id; 
      let cartIndex = this.props.cart.findIndex(function(cart){ 
       return cart._id === _id; 
      }); 
      if(cartIndex === -1){ 
       this.props.addToCart(book); 
      } 
      else{ 
       this.props.updateCart(_id, 1); 
      } 
     } 
     else { 
      this.props.addToCart(book); 
     }   
    } 

    render(){ 
     return(
      <div className="col-xs-12 col-md-6" key={this.props._id}> 
       <div className="well"> 
        <h2 className="text-center">{this.props.title}</h2> 
        <h2 className="text-center">{this.props.description} 
        </h2> 
        <h2 className="text-center">{this.props.price}</h2> 
        <button className="btn btn-success btn-block" onClick= 
        {this.handleCart}> 
         <i className="glyphicon glyphicon-shopping-cart"> 
         </i> 
         <span> Add To Cart</span> 
        </button> 
        <button className="btn btn-danger btn-block" onClick= 
        {this.deleteBookItem}> 
         <i className="glyphicon glyphicon-trash"></i> 
         <span> Delete Book</span> 
        </button> 
       </div>      
      </div> 
     ) 
    } 
} 

function mapStateToProps(state){ 
    return { 
     cart: state.cart.cart 
    } 
} 

function mapDispatchToProps(dispatch){ 
    return bindActionCreators(
     { 
      addToCart: addToCart, 
      updateCart: updateCart, 
     } 
     , dispatch); 
} 
export default connect(mapStateToProps, mapDispatchToProps)(BookItem); 

--------------------------------------------------------------------------- 

//bookActions.js 
"use strict" 

export function getBooks(){ 
    return { 
     type: 'GET_BOOKS' 
    } 
} 

export function postBook(book){ 
    return { 
     type: 'POST_BOOK', 
     payload: book 
    } 
} 

export function deleteBook(_id){ 
    return { 
     type: 'DELETE_BOOK', 
     payload: _id 
    } 
} 

export function updateBook(book){ 
    return { 
     type: 'UPDATE_BOOK', 
     payload: book 
    } 
} 

--------------------------------------------------------------------------- 
//booksReducers.js 
"use strict" 
//BOOKS REDUCERS 
let defaultBooks = [ 
    { 
    _id: 1, 
    title: 'Book 1', 
    description: 'Book 1 Description', 
    price: 19.99 
    }, 
    { 
     _id: 2, 
     title: 'Book 2', 
     description: 'Book 2 Description', 
     price: 29.99 
    }, 
    { 
    _id: 3, 
    title: 'Book 3', 
    description: 'Book 3 Description', 
    price: 39.99 
    }, 
    { 
     _id: 4, 
     title: 'Book 4', 
     description: 'Book 4 Description', 
     price: 49.99 
    }, 
    { 
    _id: 5, 
    title: 'Book 5', 
    description: 'Book 5 Description', 
    price: 59.99 
    }, 
    { 
     _id: 6, 
     title: 'Book 6', 
     description: 'Book 6 Description', 
     price: 69.99 
    } 
]; 
export function booksReducers(state = { books: defaultBooks }, action){ 

    switch(action.type){ 
    case "GET_BOOKS": 
     return {...state, books:[...state.books]} 
     break; 
    case "POST_BOOK": 
     return {...state, books:[...state.books, ...action.payload], 
     msg:'Saved! Click to continue', style:'success', 
     validation:'success'} 
     break; 
    case "POST_BOOK_REJECTED": 
     return {...state, msg:'Please, try again', style:'danger', 
     validation:'error'} 
     break; 
    case "RESET_BUTTON": 
     return {...state, msg:null, style:'primary', validation:null} 
     break; 
    case "DELETE_BOOK": 
     // Create a copy of the current array of books 
     const currentBookToDelete = [...state.books]; 
     // Determine at which index in books array is the book to be deleted 
     const indexToDelete = currentBookToDelete.findIndex(function(book){ 
      return book._id === action.payload._id; 
     }); 
     //use slice to remove the book at the specified index 
     return {books: [...currentBookToDelete.slice(0, indexToDelete), 
     ...currentBookToDelete.slice(indexToDelete + 1)]} 
     break; 

    case "UPDATE_BOOK": 
     // Create a copy of the current array of books 
     const currentBookToUpdate = [...state.books] 
     // Determine at which index in books array is the book to be deleted 
     const indexToUpdate = currentBookToUpdate.findIndex(
      function(book){ 
      return book._id === action.payload._id; 
      } 
     ) 
     // Create a new book object with the new values and with the same 
     array index of the item we want to replace. To achieve this we will 
     use ...spread but we could use concat methos too 
     const newBookToUpdate = { 
      ...currentBookToUpdate[indexToUpdate], 
      title: action.payload.title 
     } 
     // Log has the purpose to show you how newBookToUpdate looks like 
     console.log("what is it newBookToUpdate", newBookToUpdate); 
     //use slice to remove the book at the specified index, replace with 
     the new object and concatenate witht he rest of items in the array 
     return { 
      books: [...currentBookToUpdate.slice(0, indexToUpdate), 
      newBookToUpdate, ...currentBookToUpdate.slice(indexToUpdate + 1)] 
     } 
     break; 
     default: 
     break; 
    } 
    return state 
} 

[enter code here][1] 


[1]: https://i.stack.imgur.com/JCTyr.png 

답변

1

이유는 필터 기능을 사용하지? 작동 여부를 확인하십시오 :

case "DELETE_BOOK": 
    const bookId = action.payload._id; 
    return {books: state.books.filter(book => book._id !== bookId} 

그리고 switch 문의 return 후 break가 필요 없습니다.

+0

그래,이 bookReducer 코드가 나오는 튜토리얼을 따르면서 findIndex 방식을 사용했습니다. 그러나 자습서에서 드롭 다운을 사용하여 삭제하고 제출하기 때문에 프런트 엔드에서 자습서를 약간 벗어나려고 노력하고 있지만 버튼 수준에서 삭제 기능을 추가하고 싶습니다. 그러나 대신에 당신의 방식으로 보자. –

+0

자습서 링크를 게시 할 수 있습니까? –

+0

[Redux, Node js 및 MongoDB가 포함 된 전체 스택 범용] (https://www.udemy.com/full-stack-universal-react-with-redux-express-and-mongodb/?src=sac&kw=full) –