2016-06-17 9 views
13

के साथ रिएक्ट-रेडक्स और वेबसाइटॉकेट्स मैं उस तकनीक के साथ नया हूं रेक्ट-रेडक्स और मैं कुछ कार्यान्वयन के साथ आपकी सहायता चाहूंगा।socket.io

मैं सॉकेट (सॉकेट.ओओ) के साथ एक चैट एप्लिकेशन को कार्यान्वित करना चाहता हूं। सबसे पहले, उपयोगकर्ता को साइन अप करना होगा (मैं सर्वर पक्ष में पासपोर्ट का उपयोग करता हूं) और उसके बाद, अगर साइन अप सफल होता है तो उपयोगकर्ता को वेबसाकेट से कनेक्ट करना होता है।

मैंने सोचा कि सबसे अच्छा होगा सभी कार्यों के लिए एक पाइप जैसे मिडलवेयर का उपयोग करना और किस तरह की कार्रवाई मिडलवेयर प्राप्त करती है, अलग-अलग चीजें करें।

यदि कार्रवाई का प्रकार AUTH_USER है, तो क्लाइंट-सर्वर कनेक्शन बनाएं और सर्वर से आने वाली सभी घटनाएं सेट करें।

यदि कार्रवाई का प्रकार MESSAGE संदेश को संदेश भेजता है।

कोड स्निपेट्स:

----- socketMiddleware.js ----

import { AUTH_USER, MESSAGE } from '../actions/types'; 

import * as actions from 'actions/socket-actions'; 

import io from 'socket.io-client'; 

const socket = null; 

export default function ({ dispatch }) { 

    return next => action => { 

     if(action.type == AUTH_USER) { 

      socket = io.connect(`${location.host}`); 

      socket.on('message', data => { 

       store.dispatch(actions.addResponse(action.data)); 

      }); 

     } 

     else if(action.type == MESSAGE && socket) { 

      socket.emit('user-message', action.data); 

      return next(action) 

     } else { 
      return next(action) 
     } 
    } 

} 

------ index.js -------

import {createStore, applyMiddleware} from 'redux'; 

import socketMiddleware from './socketMiddleware'; 



const createStoreWithMiddleware = applyMiddleware(

    socketMiddleware 

)(createStore); 

const store = createStoreWithMiddleware(reducer); 

<Provider store={store}> 

    <App /> 

</Provider> 

उस अभ्यास के बारे में आप क्या सोचते हैं, क्या यह बेहतर कार्यान्वयन है?

+1

सामान्य रूप से इस प्रकार का प्रश्न स्टैक ओवरफ्लो के लिए उपयुक्त नहीं है, लेकिन हां, आपका दृष्टिकोण उचित दिखता है। केवल एक चीज जो मुझे "अजीब" के रूप में कूदती है केवल सशर्त रूप से 'अगली (कार्रवाई)' कहती है। आम तौर पर आप अगले मिडलवेयर (प्रेषक) को कॉल करना चाहते हैं, उदा। इसे लॉगिंग या किसी और चीज को संभालने के लिए जो आपके पास हो सकता है। – WTK

+2

यह काफी उचित दिखता है, लेकिन मैं वास्तव में रेडक्स-सागा मिडलवेयर में एक नज़र डालने की सिफारिश करता हूं, जो आपको एक विशिष्ट कार्रवाई '''' ले लेगा और इसके लिए जनरेटर को स्पिन करेगा। वहां से आप अधिक उन्नत तर्क स्थापित कर सकते हैं, जैसे कि एकाधिक चैनल, सदस्यता समाप्त, इत्यादि :) – horyd

+0

@WTK अगले मिडलवेयर को कॉल करने के संबंध में, क्या मैं अगले मध्यवर्ती को भेजने के लिए एक और शर्त जोड़ूंगा? – Ganbel

उत्तर

23

स्पोइलर: मैं वर्तमान में विकसित कर रहा हूं कि ओपन-सोर्स चैट एप्लिकेशन क्या होगा।

आप मिडलवेयर से कार्यों को अलग करके और सॉकेट क्लाइंट को मिडलवेयर से अलग करके बेहतर कर सकते हैं। इसलिए, कुछ इस तरह है, जिसके परिणामस्वरूप:

  • प्रकार -> अनुरोध, सफलता, असफलता प्रकार प्रत्येक अनुरोध (अनिवार्य नहीं) के लिए।
  • प्रसारण -> स्टोर करने के लिए अलग-अलग राज्यों
  • क्रिया -> कनेक्ट करने के लिए/डिस्कनेक्ट/फेंकना/सुनने कार्यों भेजें।
  • मिडिलवेयर -> सॉकेट क्लाइंट (socket.io) - अपने कार्यों का इलाज, और सॉकेट ग्राहक
  • ग्राहक के पास है या नहीं वर्तमान कार्रवाई करने के लिए>।

कोड के नीचे विकास किया जा रहा है जो वास्तविक एप्लिकेशन से लिया जाता है (कभी कभी कुछ संपादित), और वे स्थितियों के बहुमत के लिए पर्याप्त हैं, लेकिन SocketClient जैसे कुछ सामान 100% पूर्ण नहीं हो सकता है।

क्रिया

आप कार्रवाई संभव के रूप में सरल किया जा करना चाहते हैं, क्योंकि वे अक्सर काम दोहराया जाता है और आप शायद उनमें से बहुत सारे होने पहुंच जाएंगे।

export function send(chatId, content) { 
    const message = { chatId, content }; 
    return { 
    type: 'socket', 
    types: [SEND, SEND_SUCCESS, SEND_FAIL], 
    promise: (socket) => socket.emit('SendMessage', message), 
    } 
} 

सूचना सॉकेट एक parametrized समारोह, इस तरह से हम पूरे आवेदन भर एक ही सॉकेट उदाहरण साझा कर सकते हैं और हम किसी भी आयात के बारे में जो भी चिंता करने की ज़रूरत नहीं है (हम कैसे इसे बाद में करना दिखाता हूँ)।

मिडिलवेयर (socketMiddleware.js):

हम erikras/react-redux-universal-hot-example का उपयोग करता है के रूप में एक समान रणनीति का उपयोग करेंगे, हालांकि AJAX के बजाय सॉकेट के लिए।

हमारे सॉकेट मिडलवेयर केवल सॉकेट अनुरोधों को संसाधित करने के लिए जिम्मेदार होंगे।

मिडिलवेयर सॉकेट क्लाइंट पर कार्रवाई गुजरता है, और डिस्पैच:

  • अनुरोध (कार्रवाई types[0]): अनुरोध कर रहा है (action.type कम करने के लिए भेजा जाता है)।
  • सफलता (कार्रवाई types[1]): अनुरोध सफलता पर (action.type और action.result के रूप में सर्वर प्रतिक्रिया reducer को भेजी जाती है)।
  • विफलता (कार्रवाई types[2]): अनुरोध विफलता पर (action.type और action.error के रूप में सर्वर प्रतिक्रिया reducer को भेजी जाती है)।
export default function socketMiddleware(socket) { 
    // Socket param is the client. We'll show how to set this up later. 
    return ({dispatch, getState}) => next => action => { 
    if (typeof action === 'function') { 
     return action(dispatch, getState); 
    } 

    /* 
    * Socket middleware usage. 
    * promise: (socket) => socket.emit('MESSAGE', 'hello world!') 
    * type: always 'socket' 
    * types: [REQUEST, SUCCESS, FAILURE] 
    */ 
    const { promise, type, types, ...rest } = action; 

    if (type !== 'socket' || !promise) { 
     // Move on! Not a socket request or a badly formed one. 
     return next(action); 
    } 

    const [REQUEST, SUCCESS, FAILURE] = types; 
    next({...rest, type: REQUEST}); 

    return promise(socket) 
     .then((result) => { 
     return next({...rest, result, type: SUCCESS }); 
     }) 
     .catch((error) => { 
     return next({...rest, error, type: FAILURE }); 
     }) 
    }; 
} 

SocketClient.js

केवल एक ही है कि कभी लोड और socket.io-ग्राहक का प्रबंधन करेगा।

[वैकल्पिक] (कोड में नीचे 1 देखें)। socket.io के बारे में एक बहुत ही रोचक विशेषता यह तथ्य है कि आपके पास message acknowledgements हो सकता है, जो एक HTTP अनुरोध करते समय सामान्य जवाब होगा। हम यह सत्यापित करने के लिए उनका उपयोग कर सकते हैं कि प्रत्येक अनुरोध सही था। ध्यान दें कि इस सुविधा का उपयोग करने के लिए सर्वर socket.io आदेशों को भी यह नवीनतम पावती पैरामीटर होना चाहिए।

import io from 'socket.io-client'; 

// Example conf. You can move this to your config file. 
const host = 'http://localhost:3000'; 
const socketPath = '/api/socket.io'; 

export default class socketAPI { 
    socket; 

    connect() { 
    this.socket = io.connect(host, { path: socketPath }); 
    return new Promise((resolve, reject) => { 
     this.socket.on('connect',() => resolve()); 
     this.socket.on('connect_error', (error) => reject(error)); 
    }); 
    } 

    disconnect() { 
    return new Promise((resolve) => { 
     this.socket.disconnect(() => { 
     this.socket = null; 
     resolve(); 
     }); 
    }); 
    } 

    emit(event, data) { 
    return new Promise((resolve, reject) => { 
     if (!this.socket) return reject('No socket connection.'); 

     return this.socket.emit(event, data, (response) => { 
     // Response is the optional callback that you can use with socket.io in every request. See 1 above. 
     if (response.error) { 
      console.error(response.error); 
      return reject(response.error); 
     } 

     return resolve(); 
     }); 
    }); 
    } 

    on(event, fun) { 
    // No promise is needed here, but we're expecting one in the middleware. 
    return new Promise((resolve, reject) => { 
     if (!this.socket) return reject('No socket connection.'); 

     this.socket.on(event, fun); 
     resolve(); 
    }); 
    } 
} 

app.js

हमारे एप्लिकेशन स्टार्ट-अप पर, हम SocketClient प्रारंभ और यह दुकान विन्यास को गुजरती हैं। हमारे नए प्रारंभ दुकान middlewares (उस पैरामीटर जो हम तुमसे कहा था हम बाद में समझा जाएगा याद है?) के लिए SocketClient

const socketClient = new SocketClient(); 
const store = configureStore(initialState, socketClient, apiClient); 

configureStore.js

हम साथ socketMiddleware जोड़ें।

export default function configureStore(initialState, socketClient, apiClient) { 
const loggerMiddleware = createLogger(); 
const middleware = [ 
    ... 
    socketMiddleware(socketClient), 
    ... 
]; 

[कुछ भी नहीं विशेष] कार्रवाई प्रकार स्थिरांक

कुछ भी नहीं विशेष = आप सामान्य रूप से क्या करेंगे।

const SEND = 'redux/message/SEND'; 
const SEND_SUCCESS = 'redux/message/SEND_SUCCESS'; 
const SEND_FAIL = 'redux/message/SEND_FAIL'; 

[कुछ भी नहीं विशेष] प्रसारण

export default function reducer(state = {}, action = {}) { 
    switch(action.type) { 
    case SEND: { 
     return { 
     ...state, 
     isSending: true, 
     }; 
    } 
    default: { 
     return state; 
    } 
    } 
} 

यह बहुत काम की तरह लग सकता है, लेकिन एक बार आप यह निर्धारित किया है ऊपर यह इसके लायक है। आपका प्रासंगिक कोड पढ़ने, डीबग करना आसान होगा और आप गलतियों को कम करने के लिए कम प्रवण होंगे।

पीएस: आप AJAX API कॉल के साथ भी इस रणनीति का अनुसरण कर सकते हैं।

+0

एक आकर्षण की तरह काम करता है! मैं इस बात को समझने की कोशिश कर रहा हूं कि वास्तव में क्लाइंट को संदेश कैसे प्राप्त करें। मुझे लगता है कि आप इस पर (घटना, मज़ा) -फंक्शन का उपयोग करने के लिए अनुमान लगा रहे हैं? –

+0

@ विक्टर सरस्ट्रॉम यह वास्तव में ग्राहक है। आप इसे '(क्लाइंट) => client.on (' event ', fun)' – zurfyx

+0

का उपयोग करके किसी क्रिया में सेट अप कर सकते हैं इसे समझने के लिए प्रबंधित करें! धन्यवाद! –