我正在学习react-redux,而我们只是想从后端引入一个基本对象。我的商店目前是空的,我一直在密切关注我正在使用的教程。
文件1:“ reducer-books.js”。该文件仅定义了我要存储并传递到全局“状态”的内容。
export default function() {
return [
{ title: "Javascript: The Good Parts", pages: 101 },
{ title: "Harry Potter", pages: 39 },
{ title: "The Dark Tower", pages: 85 },
{ title: "Eloquent Ruby", pages: 1 }
;
}
文件2:“ index.js”。在这里,我将使用上面定义的Books Reducer,并通过组合reducer将它放入状态对象中(对吗?)。
import { combineReducers } from "redux";
import { BooksReducer } from "./reducer-books";
//Reducer = a function that returns a piece of the application state.
//Just a function that does that. Period.
//Because the applicaiton can have many different pieces of state, we
//can have MANY reducers.
const rootReducer = combineReducers({
books: BooksReducer
});
export default rootReducer;
文件3:“ book-list.js”,我要在其中导入此数据。但是我正在尝试打印状态,它只是空的;〜;如此困惑..我喜欢将地图状态检查为props功能,并且应该可以正常工作吗?
import React, { Component } from "react";
import { connect } from "react-redux"; // redact-redux is the glue between these two!
class BookList extends Component {
renderList() {
console.log("hmm?");
console.log(this.props);
console.log("HMMM?");
console.log(this.props.book);
console.log(this.props.books);
console.log("HMMM?3333");
console.log("HMMM?");
return this.props.books.map((book) => {
return (
<li key={book.title} className="list-group-item">
{book.title}
</li>
);
});
render() {
return (
<ul className="list-group col-sm-4">
{this.renderList()}
</ul>
)
}
}
function mapStateToProps(state) {
console.log("below hm?");
console.log(state);
return {
books: state.books
}
}
export default connect(mapStateToProps)(BookList);
文件4:app.js
import React from "react";
import { Component } from "react";
import BookList from "../containers/book-list";
export default class App extends Component {
render() {
return (
<div>
<BookList />
</div>
);
}
}
文件5:index.js(我猜这个文件是“根文件”吗?
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import App from './components/app';
import reducers from './reducers';
//Reducer = a function that returns a piece of the application state.
//Just a function that does that. Period.
//Because the applicaiton can have many different pieces of state, we
//can have MANY reducers.
const createStoreWithMiddleware = applyMiddleware()(createStore);
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<App />
</Provider>
, document.querySelector('.container'));
这是此错误的控制台输出:
bundle.js:21363 No reducer provided for key "books"
warning @ bundle.js:21363
combineReducers @ bundle.js:21448
Object.defineProperty.value @ bundle.js:22554
__webpack_require__ @ bundle.js:20
(anonymous) @ bundle.js:72
__webpack_require__ @ bundle.js:20
(anonymous) @ bundle.js:47
__webpack_require__ @ bundle.js:20
(anonymous) @ bundle.js:40
(anonymous) @ bundle.js:43
bundle.js:21363 Store does not have a valid reducer. Make sure the argument
passed to combineReducers is an object whose values are reducers.
warning @ bundle.js:21363
combination @ bundle.js:21481
dispatch @ bundle.js:21269
createStore @ bundle.js:21344
(anonymous) @ bundle.js:21611
(anonymous) @ bundle.js:86
__webpack_require__ @ bundle.js:20
(anonymous) @ bundle.js:47
__webpack_require__ @ bundle.js:20
(anonymous) @ bundle.js:40
(anonymous) @ bundle.js:43
bundle.js:22503 below hm?
bundle.js:22504 {}
bundle.js:22462 hmm?
bundle.js:22463 {books: undefined, dispatch: ƒ}
bundle.js:22464 HMMM?
bundle.js:22465 undefined
bundle.js:22466 undefined
bundle.js:22467 HMMM?3333
bundle.js:22468 HMMM?
bundle.js:22462 hmm?
bundle.js:22463 {books: undefined, dispatch: ƒ}
bundle.js:22464 HMMM?
bundle.js:22465 undefined
bundle.js:22466 undefined
bundle.js:22467 HMMM?3333
bundle.js:22468 HMMM?
bundle.js:22470 Uncaught TypeError: Cannot read property 'map' of undefined
at BookList.renderList (bundle.js:22470)
at BookList.render (bundle.js:22484)
at finishClassComponent (bundle.js:11048)
at updateClassComponent (bundle.js:11016)
at beginWork (bundle.js:11641)
at performUnitOfWork (bundle.js:14473)
at workLoop (bundle.js:14502)
at HTMLUnknownElement.callCallback (bundle.js:2759)
at Object.invokeGuardedCallbackDev (bundle.js:2797)
at invokeGuardedCallback (bundle.js:2846)
renderList @ bundle.js:22470
render @ bundle.js:22484
finishClassComponent @ bundle.js:11048
updateClassComponent @ bundle.js:11016
beginWork @ bundle.js:11641
performUnitOfWork @ bundle.js:14473
workLoop @ bundle.js:14502
callCallback @ bundle.js:2759
invokeGuardedCallbackDev @ bundle.js:2797
invokeGuardedCallback @ bundle.js:2846
replayUnitOfWork @ bundle.js:13977
renderRoot @ bundle.js:14544
performWorkOnRoot @ bundle.js:15108
performWork @ bundle.js:15029
performSyncWork @ bundle.js:15006
requestWork @ bundle.js:14906
scheduleWorkImpl @ bundle.js:14781
scheduleWork @ bundle.js:14741
scheduleRootUpdate @ bundle.js:15369
updateContainerAtExpirationTime @ bundle.js:15397
updateContainer @ bundle.js:15424
ReactRoot.render @ bundle.js:18728
(anonymous) @ bundle.js:19147
unbatchedUpdates @ bundle.js:15216
legacyRenderSubtreeIntoContainer @ bundle.js:19143
render @ bundle.js:19202
(anonymous) @ bundle.js:84
__webpack_require__ @ bundle.js:20
(anonymous) @ bundle.js:47
__webpack_require__ @ bundle.js:20
(anonymous) @ bundle.js:40
(anonymous) @ bundle.js:43
bundle.js:12302 The above error occurred in the <BookList> component:
in BookList (created by Connect(BookList))
in Connect(BookList) (created by App)
in div (created by App)
in App
in Provider
Visit <redacted>
logCapturedError @ bundle.js:12302
logError @ bundle.js:12341
commitErrorLogging @ bundle.js:12554
commitAllLifeCycles @ bundle.js:14118
callCallback @ bundle.js:2759
invokeGuardedCallbackDev @ bundle.js:2797
invokeGuardedCallback @ bundle.js:2846
commitRoot @ bundle.js:14253
completeRoot @ bundle.js:15161
@ bundle.js:15111
performWork @ bundle.js:15029
performSyncWork @ bundle.js:15006
requestWork @ bundle.js:14906
scheduleWorkImpl @ bundle.js:14781
scheduleWork @ bundle.js:14741
scheduleRootUpdate @ bundle.js:15369
updateContainerAtExpirationTime @ bundle.js:15397
updateContainer @ bundle.js:15424
ReactRoot.render @ bundle.js:18728
(anonymous) @ bundle.js:19147
unbatchedUpdates @ bundle.js:15216
legacyRenderSubtreeIntoContainer @ bundle.js:19143
render @ bundle.js:19202
(anonymous) @ bundle.js:84
__webpack_require__ @ bundle.js:20
(anonymous) @ bundle.js:47
__webpack_require__ @ bundle.js:20
(anonymous) @ bundle.js:40
(anonymous) @ bundle.js:43
bundle.js:22470 Uncaught TypeError: Cannot read property 'map' of undefined
at BookList.renderList (bundle.js:22470)
at BookList.render (bundle.js:22484)
at finishClassComponent (bundle.js:11048)
at updateClassComponent (bundle.js:11016)
at beginWork (bundle.js:11641)
at performUnitOfWork (bundle.js:14473)
at workLoop (bundle.js:14502)
at renderRoot (bundle.js:14533)
at performWorkOnRoot (bundle.js:15108)
at performWork (bundle.js:15029)
renderList @ bundle.js:22470
render @ bundle.js:22484
finishClassComponent @ bundle.js:11048
updateClassComponent @ bundle.js:11016
beginWork @ bundle.js:11641
performUnitOfWork @ bundle.js:14473
workLoop @ bundle.js:14502
renderRoot @ bundle.js:14533
performWorkOnRoot @ bundle.js:15108
performWork @ bundle.js:15029
performSyncWork @ bundle.js:15006
requestWork @ bundle.js:14906
scheduleWorkImpl @ bundle.js:14781
scheduleWork @ bundle.js:14741
scheduleRootUpdate @ bundle.js:15369
updateContainerAtExpirationTime @ bundle.js:15397
updateContainer @ bundle.js:15424
ReactRoot.render @ bundle.js:18728
(anonymous) @ bundle.js:19147
unbatchedUpdates @ bundle.js:15216
legacyRenderSubtreeIntoContainer @ bundle.js:19143
render @ bundle.js:19202
(anonymous) @ bundle.js:84
__webpack_require__ @ bundle.js:20
(anonymous) @ bundle.js:47
__webpack_require__ @ bundle.js:20
anonymous) @ bundle.js:40
(anonymous) @ bundle.js:43
contentscript.js:58 <body>…</body>
答案 0 :(得分:1)
这会让您前进:
components / app.js:
import React from "react";
import { Component } from "react";
import BookList from "../containers/book-list";
export default class App extends Component {
render() {
return (
<div>
<BookList />
</div>
);
}
}
containers / book-list.js:
import React, { Component } from "react";
import { connect } from "react-redux"; // redact-redux is the glue between these two!
class BookList extends Component {
renderList() {
return this.props.books.map((book) => {
return (
<li key={book.id} className="list-group-item">
{book.title}
</li>
);
});
}
render() {
return (
<ul className="list-group col-sm-4">
{this.renderList()}
</ul>
)
}
}
const mapStateToProps = (state) => ({
books: state.books
});
export default connect(mapStateToProps)(BookList);
index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import App from './components/app';
import reducers from './reducers';
ReactDOM.render(
<Provider store={createStore(reducers)}>
<App />
</Provider>
, document.querySelector('.container'));
reducer-books.js:
const reducer = () => {
return [
{ id: 1, title: 'Javascript: The Good Parts', pages: 101 },
{ id: 2, title: 'Harry Potter', pages: 39 },
{ id: 3, title: 'The Dark Tower', pages: 85 },
{ id: 4, title: 'Eloquent Ruby', pages: 1 }
];
};
export default reducer;
reducers.js:
import { combineReducers } from "redux";
import BooksReducer from "./reducer-books";
//Reducer = a function that returns a piece of the application state.
//Just a function that does that. Period.
//Because the applicaiton can have many different pieces of state, we
//can have MANY reducers.
const rootReducer = combineReducers({
books: BooksReducer
});
export default rootReducer;
答案 1 :(得分:0)
如果我没记错的话,这是从Stephen Grider Udemy课程开始的,是吗?我做了这个确切的课程,我可以为您提供帮助。
文件1:不幸的是,这不是设置减速器的方法。减速器只是简单地“监听”一个动作,然后根据该动作返回新的状态。对于这样的简单应用程序,我们也不需要使用组合减速器。我们可以只使用一个rootReducer。减速器应如下所示:
import * as ACTION_TYPES from '../actions/action_types';
const initialState = {
books: []
}
const rootReducer = (state = initialState, action) => {
switch (action.type) {
case ACTION_TYPES.SET_BOOKS:
return {
...state,
books: action.payload
}
case ACTION_TYPES.REMOVE_BOOKS:
return {
...state,
books: []
}
default:
return state
}
}
export default rootReducer;
现在,对于reducer的每个case语句,我们需要采取两种不同的操作。一种是删除书籍,另一种是将书籍设置为还原状态。在action_types.js文件中,声明两个操作类型,如下所示:
export const SET_BOOKS = "SET_BOOKS"
export const REMOVE_BOOKS = "REMOVE_BOOKS"
现在,在单独的actions.js文件中,创建将与reducer一起使用的动作。
import * as ACTION_TYPES from './action_types';
{type: ACTION_TYPES.SET_BOOKS}
{type: ACTION_TYPES.REMOVE_BOOKS}
export function set_books(books) {
return dispatch => {
dispatch({type: ACTION_TYPES.SET_BOOKS, payload: books})
}
}
export function remove_books() {
return dispatch => {
dispatch({type: ACTION_TYPES.REMOVE_BOOKS})
}
}
请注意set_books()函数上的“有效载荷:书籍”属性。这将是我们通过React容器将书籍保存到全局redux状态的主要方式。
现在创建一个容器,我们将使用该容器将书籍设置为全局redux状态。像这样创建一个容器:
import React, { Component } from 'react'
import { connect } from 'react-redux';
import * as ACTION_TYPES from '../store/actions/action_types';
import * as ACTIONS from '../store/actions/actions';
class Container extends Component {
books = [
{ title: "Javascript: The Good Parts", pages: 101 },
{ title: "Harry Potter", pages: 39 },
{ title: "The Dark Tower", pages: 85 },
{ title: "Eloquent Ruby", pages: 1 }
]
renderBooks = (props) => (
<div>
<p> {props.book.title} </p>
<p> {props.book.pages} </p>
</div>
)
render() {
return (
<div>
<button onClick={() => this.props.action1() } > Dispatch Action 1 </button>
<button onClick={() => this.props.action2() } > Dispatch Action 2 </button>
<button onClick={() => this.props.action_middleware1(this.books) } > Dispatch Async Middleware Action 1 </button>
<button onClick={() => this.props.action_middleware2() } > Dispatch Async Middleware Action 2 </button>
{ this.props.books
? this.props.books.map(book =>
<this.renderBooks key={book.title} book={book} />)
: null
}
</div>
)
}
}
function mapStateToProps(state) {
return {
books: state.books
};
}
function mapDispatchToProps (dispatch) {
return {
action1: () => dispatch({type: ACTION_TYPES.SET_BOOKS}),
action2: () => dispatch({type: ACTION_TYPES.REMOVE_BOOKS}),
action_middleware1: (books) => dispatch(ACTIONS.set_books(books)),
action_middleware2: () => dispatch(ACTIONS.remove_books())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Container);
请注意mapDispatchtoProps函数的action_middleware1属性。这就是我们将书籍保存到全球状态的方式。为了将书籍实际呈现到屏幕上,我们使用三元表达式,因为它是异步的。您还可以使用“调度异步中间件操作2”将书从全局状态中删除,这将自动从渲染到屏幕上删除书。
当您单击“调度异步中间件操作1”按钮时,我们初始化的“ books”对象将作为“有效负载”属性传递到该操作,然后传递到reducer并将其保存到全局状态。一旦将其保存到全局状态,我们的“ this.props.books”三元表达式将为true,并且书籍将自动呈现到屏幕上。我们的“ this.props.books”来自我们定义的mapStatetoProps函数,我们的容器通过在容器文件最底部使用的“连接”函数了解了全局还原状态。
如果尚未完成,则应像这样设置根index.js文件:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { Provider } from 'react-redux';
import rootReducer from './store/reducers/reducer';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
let store = createStore(
rootReducer,
applyMiddleware(thunk)
)
ReactDOM.render(<Provider store={store}>
<App />
</Provider>,
document.getElementById('root'));
单击“调度异步中间件1”按钮之前
点击调度异步中间件1按钮后
就是这样!这就是使应用程序正常运行所需的全部代码。
编辑:我将app.js文件保留为默认的“ create-react-app”
这是我做过的一个非常类似的应用程序的回购链接: