Отправка ответа API Socket.io на компоненты React с использованием Redux - PullRequest
0 голосов
/ 25 августа 2018

Я получаю данные, но проблема в том, что я могу получить к ним доступ только внутри одного и того же файла api.js. Как я могу сказать, это не возвращает никакого значения. Я сделал много вариаций этого фрагмента кода. Он либо возвращает initial state, либо undefined. Интересно то, что если есть error, это заполнит объект error. Извините за столько кода, но кто-то может помочь мне успешно реализовать socket.io с React/ Redux.

Вот что я получил до сих пор:

api.js
Здесь я успешно подключаюсь к API, получаю данные, но не могу использовать их вне этого файла. Если вернуть объект, это будет undefined, но если я console.log это или даже return console.log и использую файл в другом компоненте / файле, данные будут отображаться в моей консоли, но только это Кстати, и только в моей консоли ... не могу отправить данные и повторно использовать их во всем приложении, которое я пытаюсь создать.


import axios from 'axios';
import io from "socket.io-client";

export function fetchData() {

const configUrl = 'API endpoint';
    axios.get(configUrl).then(res => {        
         const socketUrl = res.data.config.liveDistributionSSL;      
            const  socket = io(socketUrl); 

            socket.on('connect', function () {            
                socket.emit('subscribe', {                 
                        subscribeMode: 'topSportBets',                 
                        language: {                    
                             default: 'en'                 
                           },
                       deliveryPlatform: 'WebSubscribe',
                       playerUuid: null,                 
                       subscribeOptions: {                     
                       autoSubscribe: true,                     
                       betCount: 3,      
                       excludeMeta: false,                     
                       resubscriptions: 0,                     
                       fullBetMeta: true,                    
                       browser: {}
                       }           
                   });


                    let relevantData = {}; // Object that I'm trying to assign values to and return


                socket.on('message', async (message) => {

                  switch (message.type) {      

                      case 'state':    // We have all the data needed to show
                        relevantData = await Object.values(Object.values(message.data)[9]);
                        break;

                        case 'currentMatches':
                        // We have matches to update
                        console.log('Matches =>', message.contentEncoding);
                        break;

                        case 'betchange':
                        // We have match bets to update
                        console.log('Match bets =>', message.contentEncoding);
                        break;

                        default: break;
                      }   
                      return relevantData;      
                   });
                   socket.on("disconnect", () => console.log("Client disconnected"));
               });
          });

        }

действия / index.js
Это мой главный создатель действий. Код, который вы видите, был моей последней попыткой опробовать новый подход, все тот же результат.


import { GET_DATA, GET_ERROR } from './types';
import { fetchData } from '../api'

export const getDataAsync = () => async dispatch => {
    try {
        const response = await fetchData();
            dispatch({ type: GET_DATA, payload: response });
    } catch (e) {
            dispatch({ type: GET_ERROR, payload: 'Something went wrong ', e });
        }
    };

редукторы / data_reducer.js
Здесь я делаю простой редуктор и в зависимости от payload меняю initial state

import { GET_DATA, GET_ERROR } from '../actions/types';

const INITIAL_STATE = {
  apiData: {},
  errorMessage: {}
};

const dataReducer = (state = INITIAL_STATE, action) => {
    switch (action.type) {
        case GET_DATA:
            return { ...state, apiData: action.payload };

        case GET_ERROR:
            return { ...state, errorMessage: action.payload };

        default:
            return state;
    }
}

export default dataReducer;

редукторы / root_reducer.js
Здесь я комбинирую редукторы, а затем внедряю мою root_reducer в мою store конфигурацию

import { combineReducers } from 'redux';
import dataReducer from './data_reducer';

const rootReducer = combineReducers({
    allData: dataReducer
});

export default rootReducer;

PrimaryLayoutContainer.js
* Это будет мой основной layout контейнер, в котором я реализую маршрутизацию, отображаю компонент PrimaryLayout и где ** я пытаюсь передать значения реквизита *

import React, { Component } from 'react';
import {connect} from 'react-redux';
import PrimaryLayout from "../components/PrimaryLayout";
import { withRouter } from 'react-router'
import * as myData from '../actions';


class PrimaryLayoutContainerComponent extends Component {
    render() {
        return (
            <div>
                <PrimaryLayout history={this.props.history}
                               allData={this.props.allData}
                />
            </div>
        )
    }
}

const mapStateToProps = (state) => {
    return {
        allData: state.allData
    }
}

export default withRouter(connect(mapStateToProps, myData)(PrimaryLayoutContainerComponent));

PrimaryLayout.js
Там, где я пытаюсь реализовать данные, всю маршрутизацию и отображение основных компонентов и т. Д., Но здесь я остановился, потому что не получаю необходимые данные

import React, {Component} from 'react';
import {Switch, Route, Redirect, Link} from 'react-router-dom';
import Favorites from './Favorites';
... a lot of other imports of my components


class PrimaryLayout extends Component {
    constructor(props) {
        super(props);
        this.state = {
            currentRoute: '',
            // data: {}
        }
    }

    componentWillReceiveProps(nextProps) {
        this.setState({
            currentRoute: nextProps.history.location.pathname
        })
    }

    componentWillMount() {
        this.setState({
            currentRoute: this.props.history.location.pathname
        })
    }

    componentDidMount() {
        console.log(this.props); // Where i'm trying to get access to the data
    }

    render() {

        const {currentRoute} = this.state;

        return (

            <div className='main-nav'>
            <nav className="topnav">
            <ul>
                <li className={currentRoute === "/favorites" ? "active" : ""}>
                    <Link to="/favorites"><div className='star'></div> Favorites </Link> </li>

                <li className={currentRoute === "/football" ? "active" : ""}>
                    <Link to="/football"><div className='football'></div> Football </Link> </li>

                <li className={currentRoute === "/basketball" ? "active" : ""}>
                    <Link to="/basketball"><div className='basketball'></div> Basketball </Link> </li>

                <li className={currentRoute === "/tennis" ? "active" : ""}>
                    <Link to="/tennis"><div className='tennis'></div> Tennis </Link> </li>

                <li className={currentRoute === "/baseball" ? "active" : ""}>
                    <Link to="/baseball"><div className='baseball'></div> Baseball </Link> </li>

                <li className={currentRoute === "/waterpolo" ? "active" : ""}>
                    <Link to="/waterpolo"><div className='waterpolo'></div> Waterpolo </Link> </li>

            </ul>
          </nav>

                <main>
                    <Switch>
                        <Route path='/favorites' component={Favorites} />
                        <Route path='/football' component={Football} />
                        <Route path='/basketball' component={Basketball} />
                        <Route path='/tennis' component={Tennis} />
                        <Route path='/baseball' component={Baseball} />
                        <Route path='/waterpolo' component={Waterpolo} />
                        <Route path='/volleyball' component={Volleyball} />
                        <Route path='/handball' component={Handball} />
                        <Route path='/formula1' component={Formula} />
                        <Redirect to="/football"/>
                    </Switch>
                </main>

            </div>
        )
    }
}


export default PrimaryLayout;

index.js
Это будет мой основной index.js файл, в котором я настраиваю элементы хранилища и рендеринга для DOM

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
import './assets/styles/App.css';

import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import rootReducer from './reducers/root_reducer';
import thunk from 'redux-thunk';

function configureStore() {
  return createStore(
    rootReducer,
    applyMiddleware(thunk)
  );
}

const myStore = configureStore();

ReactDOM.render(
  <Provider store={myStore}>
   <App />
  </Provider>,
   document.getElementById('root')
 )

Примечание:


Как я уже говорил, я успешно подключаюсь к конечной точке API, получая необходимые данные, но я могу манипулировать ими только внутри одного и того же файла api.js. Я гуглю весь день, но не нашел ничего подходящего для моей проблемы. Есть много примеров с PHP, Java, но не так много с React, Redux и т. Д. Я никогда раньше не использовал Socket.io, поэтому, пожалуйста, мои дорогие друзья, помогите мне ...: /

Главный вопрос здесь: Как я могу успешно реализовать Scoket.io и использовать Redux для отправки данных API, выбрасывая все мои основные компоненты React, вместо того, чтобы делать это очень DRY , то есть реализовывать одну и ту же логику в каждом компоненте и каждый раз получить все данные, а не только соответствующие.

Если я могу сделать это в одном месте (вне файла api.js), я могу сделать это везде, и этот ответ более чем признателен и будет принят немедленно.

1 Ответ

0 голосов
/ 04 сентября 2018

Я изменил файл api.js.async - await вызывал проблемы, плюс оператор return был не в том месте.Ошибка новичка.

import axios from 'axios';
import io from "socket.io-client";

export const fetchData = () => {

let apiData = {}; // Object that I'm trying to assign values to and return
apiData.bets = [];
apiData.matches = [];

const configUrl = 'API URI';
axios.get(configUrl).then(res => {        
        const socketUrl = res.data.config.liveDistributionSSL;      
        const  socket = io(socketUrl); 
        socket.on('connect', function () {            
            socket.emit('subscribe', {                 
                    subscribeMode: 'topSportBets',                 
                    language: {                    
                         default: 'en'                 
                       },
                   deliveryPlatform: 'WebSubscribe',
                   playerUuid: null,                 
                   subscribeOptions: {                     
                   autoSubscribe: true,                     
                   betCount: 3,      
                   excludeMeta: false,                     
                   resubscriptions: 0,                     
                   fullBetMeta: true,                    
                   browser: {}
                   }           
               });

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

              switch (message.type) {      

                case 'state':    // We have all the data needed to show
                apiData.bets = Object.assign(message.data.bets);
                apiData.matches = Object.assign(message.data.matches);
                break;

                // ... etc ...

                default: break;
                  }
               });
               socket.on("disconnect", () => console.log("Client disconnected"));
           });
      });
      return apiData;
    }

После этого я реализовал лучшую конфигурацию store.Я фактически сделал внешний файл для него, три, если быть точным, в зависимости от прогресса разработки (dev, stage, prod).Вот файл configureStore.dev.js:

import thunk from 'redux-thunk';
import {
    createStore,
    applyMiddleware,
    compose
} from 'redux';
import rootReducer from '../reducers/root_reducer';
import reduxImmutableStateInvariant from 'redux-immutable-state-invariant';

export default function configureStore(initialState) {
    return createStore(
        rootReducer,
        compose(
            applyMiddleware(thunk, reduxImmutableStateInvariant()),
            window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
        )
    );
}

И наконец то, что я сделал, чтобы все это заработало, я изменил PrimaryLayoutContainerComponent.js навыглядеть такИ со всеми этими простыми, но важными изменениями я смог получить доступ ко всем соответствующим данным, поскольку они обновлялись в режиме реального времени по всему приложению.

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import PrimaryLayout from "../components/PrimaryLayout";
import { withRouter } from 'react-router'
import * as myData from '../actions';


// Since this is our Primary Layout Container here we in addition to mapping state to props also
// are dispatching our props and binding our action creators, also using 'withRouter' HOC
// to get access to the history object’s properties and make it easy to navigate through our app.

class PrimaryLayoutContainerComponent extends Component {
    render() {
        return (
            <div>
                <PrimaryLayout history={this.props.history}
                               allData={this.props.allData}
                               getDataAsync={this.props.actions.getDataAsync}
                />
            </div>
        )
    }
}

const mapStateToProps = (state) => {
    return {allData: state.allData.apiData}
}

const mapDispatchToProps = (dispatch) => {
    return {
        actions: bindActionCreators({...myData}, dispatch)
    };
}

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(PrimaryLayoutContainerComponent));

Небольшая заметка: я всегда отвечаю на свои вопросы, вместо того, чтобы просто удалять их с помощью n, я нахожу решение самостоятельно.Я делаю это ради простого факта, что это может помочь кому-то в будущем.

...