使用 Redux 调度 Socket.io API 对 React 组件的响应
Dispatching Socket.io API response to React Components using Redux
我正在接收数据,但问题是我只能在同一个文件中访问它 api.js
。据我所知,它 return 没有任何价值。我对这段代码片段做了很多变体。它是 returning initial state
或 undefined
。有趣的是,如果有一个 error
,它会填充 error
对象。抱歉有这么多代码,但是有人可以帮助我用 React/ Redux.
成功实施 socket.io
这是我目前得到的:
api.js
这里我成功连接到 API,接收数据,但我无法在这个文件之外使用它。如果 return 一个对象它将是 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
我在这里制作了一个简单的减速器,并根据 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
这里我结合了减速器,稍后将我的 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
中操作它。我 Google 一整天,但我没有找到与我的问题相关的任何内容。 PHP、Java 的例子很多,但 React、Redux 等的例子不多……我以前从来没有用过 Socket.io
,所以请亲爱的朋友们帮助我。 ..:/
这里的主要问题是:
我怎样才能成功实现 Scoket.io 并使用 Redux 来调度 API 数据抛出我所有的主要 React 组件,而不是非常 DRY,意思是实现每个组件中都有相同的逻辑,并且每次都获取所有数据,而不仅仅是相关数据。
如果我能在一个地方(在 api.js
文件之外)做到这一点,我就可以在任何地方做到这一点,这个答案非常受欢迎,并将立即被接受。
我更改了 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 删除它们,我自己找到解决方案。我这样做是因为它可能会在将来帮助某人。
我正在接收数据,但问题是我只能在同一个文件中访问它 api.js
。据我所知,它 return 没有任何价值。我对这段代码片段做了很多变体。它是 returning initial state
或 undefined
。有趣的是,如果有一个 error
,它会填充 error
对象。抱歉有这么多代码,但是有人可以帮助我用 React/ Redux.
socket.io
这是我目前得到的:
api.js
这里我成功连接到 API,接收数据,但我无法在这个文件之外使用它。如果 return 一个对象它将是 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
我在这里制作了一个简单的减速器,并根据 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
这里我结合了减速器,稍后将我的 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
中操作它。我 Google 一整天,但我没有找到与我的问题相关的任何内容。 PHP、Java 的例子很多,但 React、Redux 等的例子不多……我以前从来没有用过 Socket.io
,所以请亲爱的朋友们帮助我。 ..:/
这里的主要问题是: 我怎样才能成功实现 Scoket.io 并使用 Redux 来调度 API 数据抛出我所有的主要 React 组件,而不是非常 DRY,意思是实现每个组件中都有相同的逻辑,并且每次都获取所有数据,而不仅仅是相关数据。
如果我能在一个地方(在 api.js
文件之外)做到这一点,我就可以在任何地方做到这一点,这个答案非常受欢迎,并将立即被接受。
我更改了 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 删除它们,我自己找到解决方案。我这样做是因为它可能会在将来帮助某人。