BotFramework V4:React WebChat无法捕获Bot发送的locationRequest事件求助
问题:Web Chat无法捕获Bot发送的locationRequest事件
你遇到的问题主要是两个核心点:Web Chat对Bot发来事件的包装逻辑,以及Redux中间件里不能直接调用组件的setState。我来一步步帮你解决:
为什么原来的代码不生效?
- 事件匹配逻辑错误:Bot发送的
locationRequest事件,在Web Chat的Redux store里会被包装成DIRECT_LINE/INCOMING_ACTIVITY类型的action,事件本身的信息存在action.payload.activity里,你直接判断action.name是找不到目标事件的。 - 不能在中间件里用
this.setState:Redux中间件的上下文和React组件完全无关,this在这里不是组件实例,调用setState要么报错,要么完全不起作用。
正确的解决方案
步骤1:修正事件捕获逻辑
我们需要监听DIRECT_LINE/INCOMING_ACTIVITY类型的action,然后检查里面的activity是否是我们要的locationRequest事件。
步骤2:用Redux规范管理状态
推荐用Redux的reducer来管理locationRequested状态,这样组件可以通过useSelector轻松获取状态变化,这也是Redux的标准用法。
完整代码示例
首先是store的创建和reducer:
// 定义一个action类型,用来更新位置请求状态 const SET_LOCATION_REQUESTED = 'SET_LOCATION_REQUESTED'; // 根reducer,初始化locationRequested为false const rootReducer = (state = { locationRequested: false }, action) => { switch (action.type) { case SET_LOCATION_REQUESTED: return { ...state, locationRequested: action.payload }; default: return state; } }; // 创建store并添加中间件 const store = createStore(rootReducer, ({ dispatch }) => next => action => { // 保留你原来的连接完成发送join事件的逻辑 if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') { dispatch({ type: 'WEB_CHAT/SEND_EVENT', payload: { name: 'webchat/join' } }); } // 监听Bot发来的活动,捕获locationRequest事件 else if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY') { const incomingActivity = action.payload.activity; // 检查是否是目标事件:类型为event,名称是locationRequest if (incomingActivity.type === 'event' && incomingActivity.name === 'locationRequest') { // dispatch更新状态的action dispatch({ type: SET_LOCATION_REQUESTED, payload: true }); } } return next(action); });
然后在你的React组件中使用这个状态:
import { useSelector } from 'react-redux'; import { WebChat, createDirectLine } from 'botframework-webchat'; function WebChatContainer() { // 从store中获取locationRequested状态 const locationRequested = useSelector(state => state.locationRequested); return ( <div> <WebChat store={store} directLine={createDirectLine({ token: '你的Direct Line Token' })} /> {/* 根据状态显示位置请求UI */} {locationRequested && <div className="location-prompt">请选择你的位置</div>} </div> ); }
如果你不想用Reducer(简化版)
如果只是简单场景,也可以在组件里订阅store的变化,不过这种方式不如reducer规范:
// 简化的store,不需要reducer const store = createStore({}, ({ dispatch }) => next => action => { if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') { dispatch({ type: 'WEB_CHAT/SEND_EVENT', payload: { name: 'webchat/join' } }); } else if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY') { const activity = action.payload.activity; if (activity.type === 'event' && activity.name === 'locationRequest') { // 发送自定义action dispatch({ type: 'LOCATION_REQUESTED', payload: true }); } } return next(action); });
组件里订阅:
import { useEffect, useState } from 'react'; import { WebChat, createDirectLine } from 'botframework-webchat'; function WebChatContainer() { const [locationRequested, setLocationRequested] = useState(false); useEffect(() => { // 订阅store变化 const unsubscribe = store.subscribe(() => { const lastAction = store.getState().lastAction; // 检查是否触发了LOCATION_REQUESTED action if (lastAction?.type === 'LOCATION_REQUESTED') { setLocationRequested(lastAction.payload); } }); // 组件卸载时取消订阅 return unsubscribe; }, []); return ( <div> <WebChat store={store} directLine={createDirectLine({ token: '你的Direct Line Token' })} /> {locationRequested && <div className="location-prompt">请选择你的位置</div>} </div> ); }
这样修改后,你的Web Chat就能正确捕获Bot发送的locationRequest事件,并更新locationRequested状态了。
内容的提问来源于stack exchange,提问作者Allain Richter
相关产品推荐
相关产品推荐

