web-dev-qa-db-fra.com

React - Application Redux: problème "Tentative non autorisée de propagation d'instance non-itérable"

Au début, cet exemple d'application fonctionnait correctement. Je pouvais voir les données que j'avais entrées sur la page du navigateur et la base de données. À l'heure actuelle, je ne peux voir les données que via la base de données, le navigateur ne les affiche pas et obtient cette erreur en plus: "Tentative invalide de répandre une instance non-itérable".

Il y a l'exemple de code:

projectActions.js

import {FETCH_BOOK, CREATE_BOOK, DELETE_BOOK} from '../actions/projectTypes';
import axios from 'axios';

const apiUrl = 'http://api/books';

export const createBookSuccess =  (data) => {
  return {
    type: CREATE_BOOK,
    payload: {
      _id: data._id,
      author: data.author,
      publication: data.publication,
      publisher: data.publisher
    }
  }
};

export const deleteBookSuccess = _id => {
  return {
    type: DELETE_BOOK,
    payload: {
      _id
    }
  }
};

export const fetchBook = (books) => {
  return {
    type: FETCH_BOOK,
    books
  }
};

export const createBook = ({ author, publication, publisher }) => {
  return (dispatch) => {
    return axios.post(`${apiUrl}`, {author, publication, publisher})
      .then(response => {
        dispatch(createBookSuccess(response.data))
      })
      .catch(error => {
        throw(error);
      });
  };
};

export const deleteBook = _id => {
  return (dispatch) => {
    return axios.delete(`${apiUrl}/${_id}`)
      .then(response => {
        dispatch(deleteBookSuccess(response.data))
      })
      .catch(error => {
        throw(error);
      });
  };
};

export const fetchAllBooks = () => {
  return (dispatch) => {
    return axios.get(apiUrl)
      .then(response => {
        dispatch(fetchBook(response.data))
      })
      .catch(error => {
        throw(error);
      });
  };
};

projectReducer.js

import {CREATE_BOOK, DELETE_BOOK, FETCH_BOOK} from '../actions/projectTypes';

const projectReducer = (state = [], action) => {
  switch (action.types) {
    case CREATE_BOOK:
      return [...state, action.payload];
    case DELETE_BOOK:
      let afterDelete = state.filter(book => {
        return book._id !== action.payload._id
      });
      return {
        ...state,
        state: afterDelete
      }
    case FETCH_BOOK:
      return action.books;
    default:
      return state;
  }
}

export default projectReducer;

rootReducer.js

import books from './projectReducer';
import {combineReducers} from 'redux';

const rootReducer = combineReducers({
    books: books
});

export default rootReducer;

BookListElement.js

import React from 'react';
import {connect} from 'react-redux';
import BookList from '../components/bookList';
import {deleteBook} from '../store/actions/projectActions';

const BookListElement= ({books, deleteBook}) => {
  if(!books.length) {
    return (
      <div>
        No Books
      </div>
    )
  }
  return (
    <div>
      {books.map(book => {
        return (
          <BookList book={book} deleteBook={deleteBook} key={book._id} />
        );
      })}
    </div>
  );
}

const mapStateToProps = state => {
  return {
    books: state.books
  };
};

const mapDispatchToProps = dispatch => {
  return {
    deleteBook: _id => {
      dispatch(deleteBook(_id));
    }
  };
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(BookListElement);

bookList.js

import React from 'react';

const styles = {
  borderBottom: '2px solid #eee',
  background: '#fafafa',
  margin: '.75rem auto',
  padding: '.6rem 1rem',
  maxWidth: '500px',
  borderRadius: '7px'
};

const BookList =  ({ book: { author, publication, publisher, _id }, deleteBook }) => {
  return (
    <div style={styles} key={_id}>
      <h2>{author}</h2>
      <p>{publication}</p>
      <p>{publisher}</p>
      <button className="btn waves-effect waves-light" type="submit" name="action" onClick={() => {deleteBook(_id)}}>
        <i className="large material-icons">delete_forever</i>
      </button>
    </div>
  );
};

export default BookList;

bookCreate.js

import React, {Component} from 'react';

class BookCreate extends Component {
  state= {
    author: '',
    publication: '',
    publisher: ''
  }

  handleChange = (e) => {
    this.setState({
      [e.target.id]: e.target.value
    });
  }

  handleSubmit = (e) => {
    e.preventDefault();
    this.props.createBook(this.state)
  }

  render() {
    return (
      <div className="container">
        <form onSubmit={this.handleSubmit} className="white" autoComplete="off">
          <h5 className="grey-text text-darken-3">Create New Book</h5>
          <div className="input-field">
            <label htmlFor="author">Author</label>
            <input type="text" id="author" onChange={this.handleChange}/>
          </div>

          <div className="input-field">
            <label htmlFor="publication">Publication</label>
            <input type="text" id="publication" onChange={this.handleChange}/>
          </div>

          <div className="input-field">
            <label htmlFor="publisher">Publisher</label>
            <input type="text" id="publisher" onChange={this.handleChange}/>
          </div>

          <div className="input-field">
            <button className="btn pink lighten-1 z-depth-0">Create</button>
          </div>
        </form>
      </div>
    )
  }
}

export default BookCreate;

J'ai vérifié le code à quelques reprises et lu un ancien billet sur ce problème, mais je n'ai trouvé aucune solution en tant que junior. Ce serait formidable si vous dites ce qui me manque.

EDIT: Ajout du fichier view.js en tant que bookList.js.

14
gilgamesh

Dans votre réducteur, l'état est supposé être un tableau, mais lors de la suppression, vous avez renvoyé un objet:

case DELETE_BOOK:
  let afterDelete = state.filter(book => {
    return book._id !== action.payload._id
  });
  return afterDelete;
12
Shubham Khatri

Cette erreur se produit lorsque vous essayez de copier un tableau non défini dans votre réducteur. par exemple:

const newList = [...state.someList];

Dans ce cas, 'someList' n'est pas défini ou n'est pas un tableau. assurez-vous que votre orthographe ou que vous utilisez un tableau correct.

7

il n'est pas nécessaire de répondre à cette question, mais peut-être que cela aidera quelqu'un qui reçoit ce message d'erreur et trébuche à travers ce message.

J'ai aussi cette erreur. Dans mon cas, l'erreur était que l'élément que j'ai essayé de cloner était en fait un objet et non un tableau!

C'est ce que j'ai fini par faire:

var clone = {...this.state.myObj};

(au lieu de)

var clone = [...this.state.myObj];

Je sais, vraiment évident mais nous commençons tous quelque part, non?

0
Tim Gerhard

je pense que vous devriez renvoyer votre réponse fetch à l'état réducteur et vous pouvez filtrer vos livres supprimés en une seule ligne. peut-être que cela fonctionnerait.

//projectReducer.js
import {CREATE_BOOK, DELETE_BOOK, FETCH_BOOK} from '../actions/projectTypes';

const projectReducer = (state = [], action) => {
  switch (action.types) {
    case CREATE_BOOK:
      return [...state, action.payload];
    case DELETE_BOOK:
      return state = state.filter(book => book._id !== action.payload._id)
    case FETCH_BOOK:
      return state = action.books;
    default:
      return state;
  }
}

export default projectReducer;
0
iambinodstha