如何在 Microsoft Bot Framework Directline JS 客户端(REACT JS)中每次都创建直线对象而不从服务器获取响应
How can I get response from the server without creating directline object everytime in Microsoft Bot Framework Direct Line JS Client (REACTJS)
我在 useEffect 中传递 getResponse()
函数,使用 userInput
作为依赖数组。每次用户发送输入时,都会触发此功能,我每次都会创建新的直线对象。我面临的问题是每次向机器人发送请求时我都在创建机器人。如何在初始渲染时仅创建一次对象,然后使用该对象与 bot 连接。
请帮忙!
Here's the botframework documentation I am following
这是我编写的用于在 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;
您应该将 DirectLine client
对象的创建以及对 activity
和 connectionStatus
的订阅移出函数 or 将 useEffect() 挂钩配置为 运行 一次。 client
对象应该创建一次,然后根据需要引用。查看讨论如何实现这些选项的 SO post。
此外,因为您已经订阅了 activity
和 connectionStatus
,所以应该允许它们独立 运行 以便它们可以按预期运行。当 connectionStatus
发生变化时,switch 语句将检测到这一点。当遇到不同的情况时,您可以通过 useState()
分配状态并通过 useEffect()
钩子检测状态的变化。
我在 useEffect 中传递 getResponse()
函数,使用 userInput
作为依赖数组。每次用户发送输入时,都会触发此功能,我每次都会创建新的直线对象。我面临的问题是每次向机器人发送请求时我都在创建机器人。如何在初始渲染时仅创建一次对象,然后使用该对象与 bot 连接。
请帮忙!
Here's the botframework documentation I am following
这是我编写的用于在 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;
您应该将 DirectLine client
对象的创建以及对 activity
和 connectionStatus
的订阅移出函数 or 将 useEffect() 挂钩配置为 运行 一次。 client
对象应该创建一次,然后根据需要引用。查看讨论如何实现这些选项的 SO post。
此外,因为您已经订阅了 activity
和 connectionStatus
,所以应该允许它们独立 运行 以便它们可以按预期运行。当 connectionStatus
发生变化时,switch 语句将检测到这一点。当遇到不同的情况时,您可以通过 useState()
分配状态并通过 useEffect()
钩子检测状态的变化。