【问题标题】:Dispatching Socket.io API response to React Components using Redux使用 Redux 向 React 组件发送 Socket.io API 响应
【发布时间】:2018-08-24 21:10:33
【问题描述】:

我正在接收数据,但问题是我只能在同一文件 api.js 中访问它。据我所知,它没有返回任何价值。我对这段代码 sn-ps 做了很多变体。它要么返回initial state,要么返回undefined。有趣的是,如果有error,它会填写error 对象。对不起这么多代码,但有人可以帮我用React/ Redux.成功实现socket.io

这是我目前得到的:

api.js
在这里,我已成功连接到 API,接收数据,但我无法在此文件之外使用它。如果a返回一个对象,它将是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"));
               });
          });

        }

actions/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 });
        }
    };

reducers/data_reducer.js
我在这里制作一个简单的 reducer,并根据 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;

reducers/root_reducer.js
我在这里组合 reducer,然后将我的 root_reducer 实现到我的 store 配置

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

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

export default rootReducer;

PrimaryLayoutContainer.js
*这将是我的主要 layout 容器,我在其中实现路由,显示 PrimaryLayout 组件,并且**我正在尝试传递值 ass props*

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 文件之外)执行此操作,我可以在任何地方执行此操作,并且非常感谢您的回答并将立即被接受。

【问题讨论】:

    标签: javascript reactjs redux socket.io redux-thunk


    【解决方案1】:

    我更改了 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 删除它们,我自己找到了解决方案。我这样做是因为它可能会在未来帮助某人。

    【讨论】:

      猜你喜欢
      • 2019-11-07
      • 2023-02-21
      • 2020-03-13
      • 2016-07-11
      • 1970-01-01
      • 2017-05-16
      • 2015-10-21
      • 2020-12-18
      • 2018-03-16
      相关资源
      最近更新 更多