我试图使用react,redux和redux-thunk创建一个实时应用程序,通过sockJS将STOMP从后端通过套接字获取对象,并在每次对象到达时更新redux存储并最终更新容器当redux存储更新时。
我的连接类通过stomp over sockjs就是这个;
class SearcButtons extends Component {
render() {
return (
<div className="searchbuttons">
<RaisedButton className="bttn" label="Start" onClick={() => this.start_twitter_stream()} />
<RaisedButton className="bttn" label="Start" onClick={() => this.stop_twitter_stream()} />
</div>
);
}
start_twitter_stream() {
let stompClient = null;
var that = this;
let socket = new SockJS('http://localhost:3001/twitterStream');
stompClient = Stomp.over(socket);
stompClient.debug = null;
stompClient.connect({}, function () {
stompClient.subscribe('/topic/fetchTwitterStream', function (tokenizedTweet) {
let tweet = JSON.parse(tokenizedTweet.body);
let payload = {
data: {
tweets: that.props.state.reducer.tweets,
}
}
payload.data.tweets.push(
{
"username": tweet.username,
"tweet": tweet.tweet,
}
);
that.props.actions.update_tweets_data(payload);
});
stompClient.send("/app/manageTwitterStream", {}, JSON.stringify({ 'command': 'start', 'message': that.props.state.reducer.keyword }));
let payload = {
data: {
socketConnection: stompClient
}
}
that.props.actions.start_twitter_stream(payload);
});
}
stop_twitter_stream() {
var socketConnection = this.props.state.reducer.socketConnection;
socketConnection.send("/app/manageTwitterStream", {}, JSON.stringify({ 'command': 'stop', 'message': null }));
socketConnection.disconnect();
let payload = {
data: {
socketConnection: null
}
}
return this.props.actions.stop_twitter_stream(payload);
}
}
SearcButtons.propTypes = {
actions: PropTypes.object,
initialState: PropTypes.object
};
function mapStateToProps(state) {
return { state: state };
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(actions, dispatch)
};
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(SearcButtons);
我在App.js中调用tweet面板容器
import TweetPanel from './containers/TweetPanel';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
class App extends Component {
render() {
return (
<MuiThemeProvider>
<div className="main">
<TweetPanel />
</div>
</MuiThemeProvider>
);
}
}
export default App;
我的侦听redux-store的容器是这样的;
class TweetPanel extends Component {
const TABLE_COLUMNS = [
{
key: 'username',
label: 'Username',
}, {
key: 'tweet',
label: 'Tweet',
},
];
render() {
console.log(this.props);
return (
<DataTables
height={'auto'}
selectable={false}
showRowHover={true}
columns={TABLE_COLUMNS}
data={
(typeof (this.props.state.reducer.tweets) !== "undefined" ) ?this.props.state.reducer.tweets : []
}
showCheckboxes={false}
onCellClick={this.handleCellClick}
onCellDoubleClick={this.handleCellDoubleClick}
onFilterValueChange={this.handleFilterValueChange}
onSortOrderChange={this.handleSortOrderChange}
page={1}
count={100}
/>
);
}
}
TweetPanel.propTypes = {
actions: PropTypes.object,
initialState: PropTypes.object
};
function mapStateToProps(state) {
return { state: state };
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(actions, dispatch)
};
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(TweetPanel);
我的行动;
import {
BUILD_TWITTER_STREAM,
START_TWITTER_STREAM,
UPDATE_TWEETS_DATA,
} from '../actions/action_types';
export function build_twitter_stream(state) {
return {
type: BUILD_TWITTER_STREAM,
payload: state
};
}
export function start_twitter_stream(state) {
return {
type: START_TWITTER_STREAM,
payload: state
};
}
export function update_tweets_data(state) {
return {
type: UPDATE_TWEETS_DATA,
payload: state
};
}
我的减速机;
import update from 'immutability-helper';
let initialState = {
socketConnection : null,
tweets : [ ]
}
export default function reducer(state = initialState, action) {
switch (action.type) {
case BUILD_TWITTER_STREAM:
return update(
state, {
socketConnection: { $set: action.payload.data.socketConnection }
}
);
case START_TWITTER_STREAM:
return update(
state, {
socketConnection: { $set: action.payload.data.socketConnection }
}
);
case UPDATE_TWEETS_DATA:
return update(
state, {
tweets: { $merge: action.payload.data.tweets }
}
);
default:
return state;
}
}
我的观察是当我尝试通过stock over Sockjs连接到socket时,我需要将上下文作为名为“that”的变量传递,您可以看到上面的第一个代码块,并在stompClient的connect函数中使用该上下文更新redux store回调,这意味着我在asynchronou函数中更新存储,当我查看Chrome的Redux devtools扩展时,redux存储更新很好,但是容器不会更新,除非我按下停止按钮触发非异步操作
在此先感谢,非常感谢您的帮助:)
答案 0 :(得分:1)
由于我遇到了类似的问题,因此我可以提供另一种方法,即函数委托方法。我在诸如RaisedButton之类的组件中创建道具。例如,我创建BindStore道具,例如:
<RaisedButton BindStore={(thatContext)=>{thatContext.state = AppStore.getState();}}... />
我还可以添加订阅者道具,例如:
<RaisedButton SubscribeStore={(thatContext) => {AppStore.subscribe(()=>{thatContext.setState(AppStore.getState())})}} ... />
在RaisedButton.js上,我可以轻松地提供thatContext:
...
constructor(props){
super(props);
if(this.props.BindStore){
this.props.BindStore(this);
}
if(this.props.SubscribeStore){
this.props.SubscribeStore(this);
}
}
...
这样做也意味着通过使用道具,一个RaisedButton可能不具有BindingStore功能或SubscribeStore功能。我还可以通过道具来呼叫商店调度员,例如:
in parent.js:
<RaisedButton PropsClick={(thatContext, thatValue) => {AppStore.dispacth(()=>
{type:"ActionType", payload:{...}})}} ... />
in RaisedButton.js
//as an example I used here dropDown, which is:
import { Dropdown } from 'react-native-material-dropdown';
//react-native-material-dropdown package has issues but the solutions are in internet :)
...
render(){
return(
<View>
<Dropdown onChangeText={(value) => {this.props.PropsClick(this, value);}} />
</View>
)
}
...
在许多示例中,例如您的父级是SearchButtons,必须渲染父级,父级必须订阅商店,因此,当任何子项更改商店时,将重新呈现所有组件群集。但是,通过这种方法,子组件将被订阅并绑定到商店。甚至一个孩子都可以调度一个动作,然后,其他相同类型的孩子订阅的函数将被回调,只有被订阅的孩子才被重新呈现。同样,您将仅将一个组件(即父组件)连接到redux存储。
//parent.js
import { connect } from 'react-redux';
import AppStore from '../CustomReducer';
...
//you will not need to set your parent's state to store state.
我并未对此方法进行过多研究,但未使用映射功能。但是,子组件将访问所有商店数据,而且在映射中,所有商店数据也都可以访问。