问题
(code from https://redux.js.org/advanced/async-actions)
The code setups a redux store and then calls dispatch on the store with some actions. The store use redux-thunk to manage async API calls.
Here is the index.js
import reduxThunk from 'redux-thunk'
const { thunkMiddleware } = reduxThunk;
import redux from 'redux';
const { createStore } = redux;
const { applyMiddleware } = redux;
import { selectSubreddit, fetchPosts } from './actions.js'
import rootReducer from './reducers.js'
const store = createStore(
rootReducer,
applyMiddleware(thunkMiddleware)
);
store.dispatch(selectSubreddit('reactjs'));
store.dispatch(fetchPosts('reactjs')).then(() => console.log(store.getState()));
Error after running node index.js
(node:19229) ExperimentalWarning: The ESM module loader is experimental.
applyMiddleware [Function: applyMiddleware]
/home/code/redux/tutorial_async_actions/node_modules/redux/lib/redux.js:648
return middleware(middlewareAPI);
^
TypeError: middleware is not a function
at /home/code/redux/tutorial_async_actions/node_modules/redux/lib/redux.js:648:16
at Array.map (<anonymous>)
at /home/code/redux/tutorial_async_actions/node_modules/redux/lib/redux.js:647:31
at createStore (/home/code/redux/tutorial_async_actions/node_modules/redux/lib/redux.js:85:33)
at file:///home/code/redux/tutorial_async_actions/index.js:18:15
at ModuleJob.run (internal/modules/esm/module_job.js:110:37)
at async Loader.import (internal/modules/esm/loader.js:164:24)
What do I do to get this to run? I think this has something to do with ES6 and modules but I'm stuck... :(
I am already doing this (as suggested by this answer)
import redux from 'redux';
const { createStore, applyMiddleware } = redux;
(I could get this to work using create-react-app ... but I would prefer to get this working without webpack et al)
Below the remaining code for reference.
Here the actions
export const SELECT_SUBREDDIT = 'SELECT_SUBREDDIT'
export function selectSubreddit(subreddit) {
return {
type: SELECT_SUBREDDIT,
subreddit
};
}
export const INVALIDATE_SUBREDDIT = 'INVALIDATE_SUBREDDIT'
function invalidateSubreddit(subreddit) {
return {
type: INVALIDATE_SUBREDDIT,
subreddit
};
}
export const REQUEST_POSTS = 'REQUEST_POSTS'
function requestPosts(subreddit) {
return {
type: REQUEST_POSTS,
subreddit
}
}
export const RECEIVE_POSTS = 'RECEIVE_POSTS'
function receivePosts(subreddit, json) {
return {
type: RECEIVE_POSTS,
subreddit,
posts: json.data.children.map(child => child.data),
receivedAt: Date.now()
}
}
export function fetchPosts(subreddit) {
return function (dispatch) {
dispatch(requestPosts(subreddit));
return fetch(`https://www.reddit.com/r/${subreddit}.json`)
.then(
response => response.json(),
error => console.log('An error occurred.', error)
)
.then(json =>
dispatch(receivePosts(subreddit, json))
)
}
}
and here the reducers
import redux from 'redux';
const { combineReducers } = redux;
import {
SELECT_SUBREDDIT,
INVALIDATE_SUBREDDIT,
REQUEST_POSTS,
RECEIVE_POSTS
} from './actions.js';
function selectedSubreddit(state = 'reactjs', action) {
switch (action.type) {
case SELECT_SUBREDDIT:
return action.subreddit
default:
return state
}
}
function posts(
state = {
isFetching: false,
didInvalidate: false,
items: []
},
action
) {
switch (action.type) {
case INVALIDATE_SUBREDDIT:
return Object.assign({}, state, { didInvalidate: true })
case REQUEST_POSTS:
return Object.assign({}, state, { isFetching: true, didInvalidate: false });
case RECEIVE_POSTS:
return Object.assign({}, state, {
isFetching: false, didInvalidate: false,
items: action.posts,
lastUpdated: action.receivedAt
});
default:
return state;
}
}
function postsBySubreddit(state = {}, action) {
switch (action.type) {
case INVALIDATE_SUBREDDIT:
case RECEIVE_POSTS:
case REQUEST_POSTS:
return Object.assign({}, state, {
[action.subreddit]: posts(state[action.subreddit], action)
});
default:
return state
}
}
const rootReducer = combineReducers({
postsBySubreddit,
selectedSubreddit
});
export default rootReducer;
Here package.json
{
"name": "redux_async_actions",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"type": "module",
"dependencies": {
"redux": "^4.0.5",
"redux-thunk": "^2.3.0"
}
}
回答1:
(I originally asked the question but I lost my login)
I got this to work using the node module system (i.e. using the function require). The ES6 export / import should work but I guess one or other of the modules I am trying to use (redux, redux-thunk) does not play nicely with ES6 export / import.
Essentially I converted the export
statements to exports.
statements
export function(...) {...}
=> exports.myFunction = function(...) {...}
And the I converted import
statements to require
statements.
import {myFunction} from './somefile.js'
=> const module = require('./somefile.js')
Below the code as in the question but using require.
index.js
const redux = require('redux');
const { createStore, applyMiddleware } = redux;
const ReduxThunk = require('redux-thunk').default
const actions = require('./actions.js');
const { selectSubreddit, fetchPosts } = actions;
const rootReducer = require('./reducers.js');
const store = createStore(
rootReducer.rootReducer,
applyMiddleware(ReduxThunk)
);
store.dispatch(selectSubreddit('reactjs'));
store.dispatch(fetchPosts('reactjs')).then(() => console.log(store.getState()));
actions.js
const fetch = require('cross-fetch');
const SELECT_SUBREDDIT = 'SELECT_SUBREDDIT'
exports.SELECT_SUBREDDIT = SELECT_SUBREDDIT
function selectSubreddit(subreddit) {
return {
type: SELECT_SUBREDDIT,
subreddit
};
}
exports.selectSubreddit = selectSubreddit;
const INVALIDATE_SUBREDDIT = 'INVALIDATE_SUBREDDIT'
exports.INVALIDATE_SUBREDDIT = INVALIDATE_SUBREDDIT
function invalidateSubreddit(subreddit) {
return {
type: INVALIDATE_SUBREDDIT,
subreddit
};
}
const REQUEST_POSTS = 'REQUEST_POSTS'
exports.REQUEST_POSTS = REQUEST_POSTS
function requestPosts(subreddit) {
return {
type: REQUEST_POSTS,
subreddit
}
}
const RECEIVE_POSTS = 'RECEIVE_POSTS'
exports.RECEIVE_POSTS = RECEIVE_POSTS
function receivePosts(subreddit, json) {
return {
type: RECEIVE_POSTS,
subreddit,
posts: json.data.children.map(child => child.data),
receivedAt: Date.now()
}
}
function fetchPosts(subreddit) {
return function (dispatch) {
dispatch(requestPosts(subreddit));
return fetch(`https://www.reddit.com/r/${subreddit}.json`)
.then(
response => response.json(),
error => console.log('An error occurred.', error)
)
.then(json =>
dispatch(receivePosts(subreddit, json))
)
}
}
exports.fetchPosts = fetchPosts;
reducers.js
const redux = require('redux');
const { combineReducers } = redux;
const actions = require('./actions.js');
const {
SELECT_SUBREDDIT,
INVALIDATE_SUBREDDIT,
REQUEST_POSTS,
RECEIVE_POSTS
} = actions;
function selectedSubreddit(state = 'reactjs', action) {
switch (action.type) {
case SELECT_SUBREDDIT:
return action.subreddit
default:
return state
}
}
function posts(
state = {
isFetching: false,
didInvalidate: false,
items: []
},
action
) {
switch (action.type) {
case INVALIDATE_SUBREDDIT:
return Object.assign({}, state, { didInvalidate: true })
case REQUEST_POSTS:
return Object.assign({}, state, { isFetching: true, didInvalidate: false });
case RECEIVE_POSTS:
return Object.assign({}, state, {
isFetching: false, didInvalidate: false,
items: action.posts,
lastUpdated: action.receivedAt
});
default:
return state;
}
}
function postsBySubreddit(state = {}, action) {
switch (action.type) {
case INVALIDATE_SUBREDDIT:
case RECEIVE_POSTS:
case REQUEST_POSTS:
return Object.assign({}, state, {
[action.subreddit]: posts(state[action.subreddit], action)
});
default:
return state
}
}
const rootReducer = combineReducers({
postsBySubreddit,
selectedSubreddit
});
exports.rootReducer = rootReducer;
package.json (notice package does not have "type": "module",
)
{
"name": "basic_example_only_node",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"cross-fetch": "^3.0.4",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0"
}
}
来源:https://stackoverflow.com/questions/60363308/how-to-use-redux-thunk-from-node-server-side