2017-10-15 7 views
0

私がやろうとしていることは、すべてのブックアイテムにdeleteItemイベントを添付することです。私はブックアイテムのIDを受け入れるアクション 'DELETE_BOOK'を持っています。そして、リデューサーでは、削除するように指定したブックアイテムなしでブックリストを返します。アイテムは削除されますが、何らかの理由で古いリスト(6アイテム)が新しいリスト(削除後5アイテム)に追加され、11アイテムになります。React/Redux - 再レンダリングすると、新しいリスト(5)に古いリスト(6)が追加され、合計11個のアイテムが削除されます。

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文での復帰後にブレークする必要はありません。

+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) –

関連する問題