【问题标题】:How to store client in redux?如何将客户端存储在redux中?
【发布时间】:2017-05-28 09:01:07
【问题描述】:

我正在设置一个需要创建客户端的 redux 应用程序。初始化后,客户端具有需要根据某些操作调用的侦听器和 API。

因此,我需要保留一个客户端实例。现在,我将其保存在该州。对吗?

所以我有以下 redux 操作创建者,但是当我想发送消息时,我需要调用 client.say(...) API。

但是我应该从哪里得到客户端对象呢?我应该从状态中检索客户端对象吗?我的理解是,这是一种 redux 反模式。使用 redux 执行此操作的正确方法是什么?

更奇怪的是,如果消息发送实际上并没有改变状态,是否应该将其视为动作创建者?

动作:

// actions.js

import irc from 'irc';

export const CLIENT_INITIALIZE = 'CLIENT_INITIALIZE';
export const CLIENT_MESSAGE_RECEIVED = 'CLIENT_MESSAGE_RECEIVED';
export const CLIENT_MESSAGE_SEND = 'CLIENT_MESSAGE_SEND';

export function messageReceived(from, to, body) {
  return {
    type: CLIENT_MESSAGE_RECEIVED,
    from: from,
    to: to,
    body: body,
  };
};

export function clientSendMessage(to, body) {
  client.say(...); // <--- where to get client from?
  return {
    type: CLIENT_MESSAGE_SEND,
    to: to,
    body: body,
  };
};

export function clientInitialize() {
  return (dispatch) => {
    const client = new irc.Client('chat.freenode.net', 'react');

    dispatch({
      type: CLIENT_INITIALIZE,
      client: client,
    });

    client.addListener('message', (from, to, body) => {
      console.log(body);
      dispatch(messageReceived(from, to, body));
    });
  };
};

这里是减速器:

// reducer.js
import { CLIENT_MESSAGE_RECEIVED, CLIENT_INITIALIZE } from '../actions/client';
import irc from 'irc';

export default function client(state: Object = { client: null, channels: {} }, action: Object) {
  switch (action.type) {
    case CLIENT_MESSAGE_RECEIVED:
      return {
        ...state,
        channels: {
          ...state.channels,
          [action.to]: [
            // an array of messages
            ...state.channels[action.to],
            // append new message
            {
              to: action.to,
              from: action.from,
              body: action.body,
            }
          ]
        }
      };

    case CLIENT_JOIN_CHANNEL:
      return {
        ...state,
        channels: {
          ...state.channels,
          [action.channel]: [],
        }
      };

    case CLIENT_INITIALIZE:
      return {
        ...state,
        client: action.client,
      };
    default:
      return state;
  }
}

【问题讨论】:

    标签: reactjs redux react-redux redux-thunk


    【解决方案1】:

    使用中间件将客户端对象注入动作创建者! :)

    export default function clientMiddleware(client) {
      return ({ dispatch, getState }) => {
        return next => (action) => {
          if (typeof action === 'function') {
            return action(dispatch, getState);
          }
    
          const { promise, ...rest } = action;
          if (!promise) {
            return next(action);
          }
    
          next({ ...rest });
    
          const actionPromise = promise(client);
          actionPromise.then(
            result => next({ ...rest, result }),
            error => next({ ...rest, error }),
          ).catch((error) => {
            console.error('MIDDLEWARE ERROR:', error);
            next({ ...rest, error });
          });
    
          return actionPromise;
        };
      };
    }
    

    然后应用它:

    const client = new MyClient();
    
    const store = createStore(
      combineReducers({
        ...
      }),
      applyMiddleware(clientMiddleware(client))
    );
    

    然后你可以在动作创建者中使用它:

    export function actionCreator() {
      return {
        promise: client => {
          return client.doSomethingPromisey();
        }
      };
    }
    

    这主要改编自react-redux-universal-hot-example boilerplate project。我删除了允许您定义启动、成功和失败操作的抽象,用于创建this abstraction in action creators

    如果你的客户端不是异步的,你可以修改这段代码,简单的传入客户端,类似于 redux-thunk 传入dispatch

    【讨论】:

      猜你喜欢
      • 2019-02-09
      • 1970-01-01
      • 2017-02-07
      • 2020-11-04
      • 2013-03-17
      • 2020-11-03
      • 2021-09-24
      • 2020-10-12
      相关资源
      最近更新 更多