javascript - 如何在不每次在 Microsoft Bot Framework Direct Line JS Client (REACTJS) 中创建直线对象的情况下从服务器获取响应
问题描述
我getResponse()
将 useEffect 中的函数userInput
作为依赖数组传递。每次用户发送输入时,都会触发此功能,并且每次都会创建新的直线对象。我面临的问题是每次向机器人发送请求时我都在创建机器人。如何在初始渲染时只创建一次对象,然后使用该对象与机器人连接。
请帮忙!
这是我为在 ReactJS 中与 bot 通信而编写的代码。
import React, { useEffect, useState } from "react";
import "./App.css"
import { DirectLine } from "botframework-directlinejs";
import { browserName, browserVersion, osName } from "react-device-detect";
import { ConnectionStatus } from 'botframework-directlinejs';
import Header from "./Components/Header";
import MainBody from "./Components/MainBody";
import BottomWrapper from "./Components/BottomWrapper";
function App() {
useEffect(() => {
const userIpDetails = fetchIp();
setUserIp(userIpDetails);
}, []);
// to fetch user IP
const fetchIp = async () => {
const response = await fetch("https://api.ipify.org/?format=json");
const ip = await response.json();
const userIP = ip.ip;
return userIP;
};
const [loaded, setLoaded] = useState(false);
const [message, setMessage] = useState("");
const [userInput, setUserInput] = useState([]);
const [messages, setMessages] = useState([]);
const [userIp, setUserIp] = useState("");
var client;
useEffect(() => {
setLoaded(true);
getResponse();
}, [userInput]);
// to get DirectLine Streaming Token
const getDirectLineStreamingToken = async function () {
const res = await fetch(
https://directline.botframework.com/v3/directline/tokens/generate,
{
method: "POST",
headers: {
Authorization:
`Bearer TOKEN`,
},
}
);
const { token } = await res.json();
return token;
};
// send request via message box
const sendRequest = () => {
console.log("request sent");
client
?.postActivity({
from: {
id: "my_id",
name: "Software Company",
avatarUrl:
"https://demos.telerik.com/kendo-ui/content/chat/VacationBot.png",
},
type: "message",
text: message,
channelData: {
iP: userIp,
platform: `${osName}`,
Browser: `${browserName} ${browserVersion}`,
},
})
?.subscribe(
(id) => console.log("Posted activity, assigned ID ", id),
(error) => console.log("Error posting activity", error)
);
};
// receive response from server
const getResponse = function () {
getDirectLineStreamingToken().then(function (token) {
client = new DirectLine({
domain: "https://directline.botframework.com/v3/directline",
token: token,
});
client.activity$.subscribe((activity) => {
onResponse(activity);
});
client.connectionStatus$
.subscribe(connectionStatus => {
switch(connectionStatus) {
case ConnectionStatus.Uninitialized: // the status when the DirectLine object is first created/constructed
case ConnectionStatus.Connecting: // currently trying to connect to the conversation
case ConnectionStatus.Online: // successfully connected to the converstaion. Connection is healthy so far as we know.
case ConnectionStatus.ExpiredToken: // last operation errored out with an expired token. Your app should supply a new one.
case ConnectionStatus.FailedToConnect: // the initial attempt to connect to the conversation failed. No recovery possible.
case ConnectionStatus.Ended: // the bot ended the conversation
}
console.log("connection status ", connectionStatus)
});
})
.catch((e) => console.log("bot error", e));;
};
// handle response received from server
const onResponse = function (activity) {
console.log("activity is ", activity);
let receivedResponse = activity.text;
if (activity.inputHint === "acceptingInput") {
setMessages([
...messages,
{ messageKey: receivedResponse, isbotmessage: true },
]);
}
};
const handleChange = function (event) {
setMessage(event.target.value);
console.log(event.target.value);
};
const handleKeyPress = function (event) {
if (event.key === "Enter") {
sendRequest();
setMessages([...messages, { messageKey: message, isbotmessage: false }]);
setUserInput([
...messages,
{ messageKey: userInput, isbotmessage: false },
]);
}
};
const handleClick = function (event) {
sendRequest();
setMessages([...messages, { messageKey: message, isbotmessage: false }]);
setUserInput([...messages, { messageKey: userInput, isbotmessage: false }]);
};
return loaded ? (
<div className="App">
<div className="chat-window">
<Header />
<MainBody messages={messages}/>
<BottomWrapper message={message} handleChange={handleChange} handleKeyPress={handleKeyPress} handleClick={handleClick}/>
</div>
</div>
) : (
<p>Loading...</p>
);
}
export default App;
解决方案
您应该将 DirectLineclient
对象的创建以及订阅activity
andconnectionStatus
移出函数或将 useEffect() 挂钩配置为仅运行一次。该client
对象应创建一次,然后根据需要引用。查看这篇讨论如何实现这些选项的 SO帖子。
此外,由于您已经订阅了activity
and connectionStatus
,因此应该允许它们独立运行,以便它们可以按预期运行。当connectionStatus
发生变化时,switch 语句会检测到这一点。当遇到不同的情况时,您可以通过钩子分配状态useState()
并检测对状态的更改。useEffect()
推荐阅读
- bigcommerce - 基石有没有办法通过 url 注入 html?
- python - 当部分单词包含特殊字符时,Python正则表达式匹配单词边界
- excel - 使用 For 循环选择 Access 中的特定字段并将它们粘贴到 Excel
- java - 当我的布局中的 NestedScrollView 在其下方添加更多小视图时,它变得迟缓
- django - 使用 Django 和 Angular 进行 Windows 身份验证?
- html - 当 col-*-* 存在时,Bootsrap col-* 不起作用,但它应该是默认值
- tensorflow - 交叉熵损失的权重
- kubernetes-helm - Helm 控制输入值
- java - Realm 中的 getDefaultInstance() 和 getInstance() 有什么区别?
- airflow - 气流任务的优先级未得到遵守