【问题标题】:How to use redux-thunk from node server side?如何从节点服务器端使用 redux-thunk?
【发布时间】:2020-06-07 08:07:59
【问题描述】:

(来自https://redux.js.org/advanced/async-actions的代码)

代码设置了一个 redux 存储,然后通过一些操作在存储上调用 dispatch。商店使用 redux-thunk 来管理异步 API 调用。

这里是 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()));

运行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)

我该怎么做才能让它运行?我认为这与 ES6 和模块有关,但我被卡住了...... :(

我已经在这样做了(正如this answer 所建议的那样)

import redux from 'redux';
const { createStore, applyMiddleware } = redux;

(我可以使用 create-react-app 让它工作......但我更愿意在没有 webpack 等的情况下让它工作)


下面剩余代码供参考。

这里是动作

    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))
          )
      }
    }

这里是减速器

    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;

这里是 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"
      }
    }

【问题讨论】:

  • 这能回答你的问题吗? ES6 imports in Node with --experimental-modules
  • @Zydnar 我已经更新了我的问题。我已经这样做了(首先导入整个模块然后解构)。
  • 对目标节点使用 babel 是完全可以的,特别是如果你的代码应该适用于不同版本的节点,我不确定是否使用 webpack,因为 webpack 更适用于 WEB。所以也许只使用 babel?
  • 谢谢,我没有想到 babel。我试试看。

标签: node.js redux redux-thunk es6-modules


【解决方案1】:

(我最初问了这个问题,但我失去了登录名)

我使用node module system(即使用函数require)让它工作。 ES6 导出/导入应该可以工作,但我想我尝试使用的一个或其他模块(redux、redux-thunk)不能很好地与 ES6 导出/导入配合使用。

基本上我将export 语句转换为exports. 语句

export function(...) {...} => exports.myFunction = function(...) {...}

我将import 语句转换为require 语句。

import {myFunction} from './somefile.js'=> const module = require('./somefile.js')

在问题中的代码下方,但使用 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(注意包没有"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"
      }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-29
    • 2021-10-26
    • 2015-12-09
    • 1970-01-01
    • 1970-01-01
    • 2019-11-01
    • 1970-01-01
    • 2020-12-14
    相关资源
    最近更新 更多