5

Tried two ways:

  1. call connectToServer() from action creator within Starter component in componentDidMount(); and dispatch like this:

    let socket = new Socket('ws://address/socket');
    
    socket.connect();
    
    dispatch({
      type: Constants.SESSION_SAVE_SOCKET,
      socket: socket,
    });
    
    const lobbyChannel = socket.channel('lobby');
    
    lobbyChannel.join()
    .receive('ok', () => {         
      dispatch({
        type: Constants.SESSION_LOBBYCHANNEL_RECEIVE_OK,
      });
    
      dispatch({
        type: Constants.SESSION_SAVE_LOBBYCHANNEL,
        lobbyChannel: lobbyChannel,
      });
    
    }).receive('error', (payload) => {            
        dispatch({
          type: Constants.SESSION_LOBBYCHANNEL_RECEIVE_ERROR,
        });
    });
    

Next I receive state by redux's mapStateToProps connect. The result is component is called four times and props are empty at the result.

  1. put all logic into the reducer, but the result is: component is rendered with empty props (undefined properties) and moment after I see in console logs that connection is established, but component is already rendered.

How to deal with such a issue? Thanks for any suggestions.

Tom Hubbard
  • 15,820
  • 14
  • 59
  • 86
mike00
  • 438
  • 1
  • 6
  • 17

1 Answers1

4

The way I found that works is to setup your own middleware for the socket like so.

import {createStore, applyMiddleware} from 'redux';
import startWs, {wsMiddleware} from './ws.api';

function handleData(state = {data1: {}}, action) {
  switch (action.type) {
    case 'ApiGotData': return Object.assign({}, state, {data1: action.data});
    default: return state;
  }
}

const store = createStore(handleData, applyMiddleware(wsMiddleware));

startWs(store);

export default store;

import * as Actions from './Actions';

var socket = null;

const newData = {
  'React version': '15',
  'Project': 'Redux with socket.io',
  'currentDateTime': new Date().toLocaleString()
};

export function wsMiddleware() {
  return (next) => (action) => {
    if (socket && action.type === 'ApiGetData') {
      console.log('ApiGetData');
      socket.emit('client:GetData', {});
    } else if (socket && action.type === 'ApiSetData') {
      console.log('ApiSetData');
      socket.emit('client:SetData', action.data);
    }

    return next(action);
  };
}

export default function (store) {
  socket = new io();

  socket.on('server:GetDataDone', (data) => {
    console.log('GetDataDone');
    store.dispatch(Actions.apiGotData(data));
  });

  socket.on('server:SetDataDone', () => {
    console.log('SetDataDone');
    store.dispatch(Actions.apiGetData());
  });
  
  store.dispatch(Actions.apiSetData(newData));
}

The project example is ReduxSocketIO at https://github.com/jmarkstevens/ReactPatterns.

J. Mark Stevens
  • 4,911
  • 2
  • 13
  • 18
  • 1
    Thanks Mark, Actually I've used my first approach but instead of waiting for props within the same component I rather separate this and now it's look like: first component is responsible to connect, and result are shown in the next one. – mike00 Feb 21 '17 at 07:08
  • Thanks, you really help with that! – Oleg Baranovsky Oct 12 '17 at 12:02