Javascript React - Redux App:“传播不可迭代实例的尝试无效”问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/52699646/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
React - Redux App: "Invalid attempt to spread non-iterable instance" Issue
提问by gilgamesh
At the beginning, that sample app was working properly. I could see data that I inputted over browser page and database. At now, I can see the data only via the database, the browser doesn't show data and getting this error additionally: "Invalid attempt to spread non-iterable instance".
一开始,该示例应用程序运行正常。我可以看到我通过浏览器页面和数据库输入的数据。目前,我只能通过数据库查看数据,浏览器不显示数据并另外收到此错误:“传播不可迭代实例的尝试无效”。
There is the sample code :
有示例代码:
projectActions.js
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
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
rootReducer.js
import books from './projectReducer';
import {combineReducers} from 'redux';
const rootReducer = combineReducers({
books: books
});
export default rootReducer;
BookListElement.js
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
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
书创建.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;
I checked the code a few times and read an older post about this issue but I didn't find any solution as a junior. That would be great if you say what did I miss.
我检查了几次代码并阅读了一篇关于这个问题的旧帖子,但作为一名大三学生,我没有找到任何解决方案。如果你说我错过了什么,那就太好了。
EDIT: Added view.js file as bookList.js .
编辑:添加 view.js 文件作为 bookList.js 。
回答by Shubham Khatri
In your reducer, the state is supposed to be an array, but during deletion, you have returned an object:
在您的减速器中,状态应该是一个数组,但是在删除过程中,您返回了一个对象:
case DELETE_BOOK:
let afterDelete = state.filter(book => {
return book._id !== action.payload._id
});
return afterDelete;
回答by Nalan Madheswaran
This error happens when you trying to copy an undefined array in your reducer. eg:
当您尝试在减速器中复制未定义的数组时会发生此错误。例如:
const newList = [...state.someList];
In this case 'someList' is undefined or not an array. make sure your spelling or you are using an correct array.
在这种情况下,'someList' 未定义或不是数组。确保您的拼写或您使用的是正确的数组。
回答by Tim Gerhard
not necessary answering this question but maybe this helps someone who gets this error message and stumbles accross this SO-Post
没有必要回答这个问题,但也许这可以帮助那些收到此错误消息并偶然发现此 SO-Post 的人
I got this error as well. In my case the error was that the element I tried to clone was in fact an object and not an array!
我也收到了这个错误。就我而言,错误是我尝试克隆的元素实际上是一个对象而不是数组!
This was what I ended up doing instead:
这就是我最终做的事情:
var clone = {...this.state.myObj};
(instead of)
(代替)
var clone = [...this.state.myObj];
I know, really obvious but we all start somewhere, right?
我知道,很明显,但我们都从某个地方开始,对吗?
回答by iambinodstha
I think you should return your fetch response to reducer state and you can filter your deleted books in one line. maybe this would work.
我认为您应该将 fetch 响应返回到 reducer 状态,并且您可以在一行中过滤已删除的书籍。也许这会奏效。
//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;

