Reactjs Redux Observable和Rxjs不捕获第一个事件,但捕获第二个事件
我一直在开发一个聊天机器人应用程序,它是用Typescript编写的,使用rxjs的Redux Observable。我试图将一个click事件从Shell.tsx组件发送到我的redux存储,它首先被rxjs Epic截获,然后被发送到redux存储。但是我的redux商店的返回状态不会影响应该在单击事件上进行的更改,但是它会在第二次单击时返回预期结果 这是my Shell.tsx的一部分,它包含相关的组件方法,这些组件方法将click事件作为对存储的操作触发:Reactjs Redux Observable和Rxjs不捕获第一个事件,但捕获第二个事件,reactjs,typescript,redux,rxjs,observable,Reactjs,Typescript,Redux,Rxjs,Observable,我一直在开发一个聊天机器人应用程序,它是用Typescript编写的,使用rxjs的Redux Observable。我试图将一个click事件从Shell.tsx组件发送到我的redux存储,它首先被rxjs Epic截获,然后被发送到redux存储。但是我的redux商店的返回状态不会影响应该在单击事件上进行的更改,但是它会在第二次单击时返回预期结果 这是my Shell.tsx的一部分,它包含相关的组件方法,这些组件方法将click事件作为对存储的操作触发: import * as
import * as React from 'react';
import { ChatState, FormatState } from './Store';
import { User } from 'botframework-directlinejs';
import { classList } from './Chat';
import { Dispatch, connect } from 'react-redux';
import { Strings } from './Strings';
import { createStore, ChatActions, sendMessage } from './Store';
import { Subscription } from 'rxjs/Subscription';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/fromEvent';
import 'rxjs/add/observable/merge';
interface Props {
inputText: string,
strings: Strings,
isActive: boolean,
onChangeText: (inputText: string) => void,
sendMessage: (inputText: string) => void
checkActive: (isChatActive: boolean) => void
}
private handleChatClick(isChatActive) {
this.store.dispatch({type: 'Chat_Activate', isChatActive: true})
setTimeout(() => {
this.store.subscribe(() => {
this.isActive = this.store.getState().shell.isChatActive
})
console.log(this.isActive)
}, 3000)
if (this.isActive) {
this.forceUpdate()
}
// this.props.checkActive(true)
}
render() {
//other code
return (
<div className={ className }>
<div className="wc-textbox">
{
console.log('chat rendered')
}
<input
type="text"
className="wc-shellinput"
ref={ input => this.textInput = input }
value={ this.props.inputText }
onChange={ _ => this.props.onChangeText(this.textInput.value) }
onKeyPress={ e => this.onKeyPress(e) }
placeholder={ placeholder }
aria-label={ this.props.inputText ? null : placeholder }
aria-live="polite"
// onFocus={ this.props.handleChatClick}
onClick={() => {
this.handleChatClick(true)
}}
/>
</div>
</div>
);
}
export const Shell = connect(
(state, ownProps) => {
return {
inputText: state.shell.input,
strings: state.format.strings,
isActive: state.shell.isChatActive,
// only used to create helper functions below
locale: state.format.locale,
user: state.connection.user
}
}
, {
// passed down to ShellContainer
onChangeText: (input: string) => ({ type: 'Update_Input', input, source: "text" } as ChatActions),
// only used to create helper functions below
sendMessage
}, (stateProps: any, dispatchProps: any, ownProps: any): Props => ({
// from stateProps
inputText: stateProps.inputText,
strings: stateProps.strings,
isActive: stateProps.isActive,
// from dispatchProps
onChangeText: dispatchProps.onChangeText,
checkActive: dispatchProps.checkActive,
// helper functions
sendMessage: (text: string) => dispatchProps.sendMessage(text, stateProps.user, stateProps.locale),
}), {
withRef: true
}
)(ShellContainer);
import*as React from'React';
从“/Store”导入{ChatState,FormatState};
从'botframework directlinejs'导入{User};
从“/Chat”导入{classList};
从“react-redux”导入{Dispatch,connect};
从“/Strings”导入{Strings};
从“/Store”导入{createStore、ChatActions、sendMessage};
从'rxjs/Subscription'导入{Subscription};
从“rxjs/Observable”导入{Observable};
导入“rxjs/add/observable/fromEvent”;
导入“rxjs/add/observable/merge”;
界面道具{
输入文本:字符串,
弦:弦,
isActive:布尔值,
onChangeText:(inputText:string)=>void,
sendMessage:(inputText:string)=>void
checkActive:(isChatActive:boolean)=>void
}
专用手柄ChatClick(iChatActive){
this.store.dispatch({type:'Chat_Activate',isChatActive:true})
设置超时(()=>{
this.store.subscribe(()=>{
this.isActive=this.store.getState().shell.isChatActive
})
console.log(this.isActive)
}, 3000)
如果(this.isActive){
这个.forceUpdate()文件
}
//this.props.checkActive(true)
}
render(){
//其他代码
返回(
{
console.log('chat rendered')
}
this.textInput=input}
值={this.props.inputText}
onChange={{{{>this.props.onChangeText(this.textInput.value)}
onKeyPress={e=>this.onKeyPress(e)}
占位符={占位符}
aria标签={this.props.inputText?null:占位符}
aria live=“礼貌”
//onFocus={this.props.handleChatClick}
onClick={()=>{
此.handleChatClick(true)
}}
/>
);
}
export const Shell=connect(
(状态,ownProps)=>{
返回{
inputText:state.shell.input,
字符串:state.format.strings,
isActive:state.shell.isChatActive,
//仅用于创建下面的帮助器函数
语言环境:state.format.locale,
用户:state.connection.user
}
}
, {
//传给贝壳容器
onChangeText:(输入:字符串)=>({type:'Update_input',input,source:'text}作为ChatActions),
//仅用于创建下面的帮助器函数
发送消息
},(stateProps:any,dispatchProps:any,ownProps:any):Props=>({
//来自国家支柱
inputText:stateProps.inputText,
字符串:stateProps.strings,
isActive:stateProps.isActive,
//从调度道具
onChangeText:dispatchProps.onChangeText,
checkActive:dispatchProps.checkActive,
//辅助函数
sendMessage:(text:string)=>dispatchProps.sendMessage(text,stateProps.user,stateProps.locale),
}), {
withRef:true
}
)(贝壳容器);
这是my Store.ts代码的一部分:
export interface ShellState {
sendTyping: boolean
input: string,
isChatActive: boolean,
isPinging: boolean
}
export const setChatToActive = (isChatActive: boolean) => ({
type: 'Chat_Activate',
isChatActive: isChatActive,
} as ChatActions);
export const ping = (isPinging: boolean) => ({
type: 'Is_Pinging',
isPinging: isPinging
} as ChatActions)
export type ShellAction = {
type: 'Update_Input',
input: string
source: "text"
} | {
type: 'Card_Action_Clicked'
} | {
type: 'Set_Send_Typing',
sendTyping: boolean
} | {
type: 'Send_Message',
activity: Activity
} | {
type: 'Chat_Activate',
isChatActive: boolean
} | {
type: 'Is_Pinging',
isPinging: boolean
}
export const shell: Reducer<ShellState> = (
state: ShellState = {
input: '',
sendTyping: false,
isChatActive: false,
isPinging: false
},
action: ShellAction
) => {
console.log(state)
switch (action.type) {
case 'Update_Input':
return {
... state,
input: action.input
};
case 'Send_Message':
return {
... state,
input: ''
};
case 'Chat_Activate':
const newState = {
...state,
isChatActive: action.isChatActive
}
return newState
case 'Set_Send_Typing':
return {
... state,
sendTyping: action.sendTyping
};
case 'Card_Action_Clicked':
return {
... state
};
case 'Is_Pinging':
const newPing = {
... state,
isPinging: action.isPinging
}
return newPing;
default:
return state;
}
}
// 2. Epics
//************************************************************************
//Import modules
import { applyMiddleware } from 'redux';
import { Epic } from 'redux-observable';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/delay';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/merge';
import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/operator/mapTo';
import 'rxjs/add/operator/throttleTime';
import 'rxjs/add/operator/takeUntil';
import 'rxjs/add/observable/bindCallback';
import 'rxjs/add/observable/empty';
import 'rxjs/add/observable/of';
//************************************************************************
//Asynchronously send messages
const sendMessageEpic: Epic<ChatActions, ChatState> = (action$, store) =>
action$.ofType('Send_Message')
.map(action => {
const state = store.getState();
const clientActivityId = state.history.clientActivityBase + (state.history.clientActivityCounter - 1);
return ({ type: 'Send_Message_Try', clientActivityId } as HistoryAction);
});
const setChatToActiveEpic: Epic<ChatActions, ChatState> = (action$, store) =>
action$.ofType('Chat_Activate')
.mapTo({type: 'Chat_Activate', isChatActive: true} as ChatActions)
.takeUntil(
action$.ofType('Chat_Activate')
)
const pingEpic: Epic<ChatActions, ChatState> = (action$, store) =>
action$.ofType('Is_Pinging')
.mapTo({type: 'Is_Pinging', isPinging: true} as ChatActions)
.takeUntil(
action$.ofType('Is_Pinging')
)
// 3. Now we put it all together into a store with middleware
import { Store, createStore as reduxCreateStore, combineReducers } from 'redux';
import { combineEpics, createEpicMiddleware } from 'redux-observable';
export const createStore = () =>
reduxCreateStore(
combineReducers<ChatState>({
shell,
format,
size,
connection,
history
}),
applyMiddleware(createEpicMiddleware(combineEpics(
updateSelectedActivityEpic,
sendMessageEpic,
trySendMessageEpic,
retrySendMessageEpic,
showTypingEpic,
sendTypingEpic,
setChatToActiveEpic,
pingEpic
)))
);
export type ChatStore = Store<ChatState>;
导出接口外壳状态{
发送类型:布尔
输入:字符串,
isChatActive:布尔值,
isping:布尔值
}
export const setChatToActive=(isChatActive:boolean)=>({
键入:“聊天\激活”,
isChatActive:isChatActive,
}作为行动);
导出常量ping=(isping:boolean)=>({
类型:“正在进行中”,
isping:isping
}(作为行动)
导出类型ShellAction={
键入:“更新输入”,
输入:字符串
资料来源:“文本”
} | {
键入:“卡片\操作\单击”
} | {
键入:“设置\发送\键入”,
发送类型:布尔
} | {
键入:“发送消息”,
活动:活动
} | {
键入:“聊天\激活”,
isChatActive:布尔值
} | {
类型:“正在进行中”,
isping:布尔值
}
导出常量外壳:减速机=(
状态:ShellState={
输入:“”,
sendTyping:false,
isChatActive:错误,
isPinging:错误
},
行动:炮弹行动
) => {
console.log(状态)
开关(动作类型){
案例“更新输入”:
返回{
……国家,
输入:action.input
};
案例“发送消息”:
返回{
……国家,
输入:“”
};
案例“聊天室激活”:
常数newState={
……国家,
isChatActive:action.isChatActive
}
返回新闻状态
案例“设置\发送\键入”:
返回{
……国家,
sendTyping:action.sendTyping
};
案例“卡片行动点击”:
返回{
…州
};
“正在”案例:
常数newPing={
……国家,
isping:action.isping
}
返回新平;
违约:
返回状态;
}
}
// 2. 史诗
//************************************************************************
//导入模块
从'redux'导入{applyMiddleware};
从'redux observable'导入{Epic};
从rxjs导入{Observable}/
export const shell: Reducer<ShellState> = (
state: ShellState = {
input: '',
sendTyping: false,
isChatActive: false,
isPinging: false
},
action: ShellAction
) => {
console.log(state)
// this updates the store
this.store.dispatch({type: 'Chat_Activate', isChatActive: true})
// 3 seconds later, you're listening for store changes, but it's already changed
setTimeout(() => {
this.store.subscribe(() => {
this.isActive = this.store.getState().shell.isChatActive
})
// then you console.log this.isActive which might be false because that's the initial state in the reducer
console.log(this.isActive)
}, 3000)
this.store.subscribe(() => {
this.isActive = this.store.getState().shell.isChatActive;
});
this.store.dispatch({type: 'Chat_Activate', isChatActive: true});
private handleChatClick(isChatActive) {
console.log(`before click/chat active event: ${this.store.getState().shell.isChatActive}`);
this.store.dispatch({type: 'Chat_Activate', isChatActive: true})
console.log(`after click/chat active event: ${this.store.getState().shell.isChatActive}`);
}