![](/img/trans.png)
[英]Flutter Firebase real time database not storing values outside of listener code
[英]Collaborative online code editor sets infinite loop on firebase real time database
我试图建立一个协作的在线代码编辑器。 除了每次在代码编辑器中进行更改时进行更改的屏幕之外,我想更新所有屏幕。
目标是:
[代码编辑器]
Firebase:
但是,当我对 firebase 使用 onValue 侦听器时,会出现一个无限循环。我该如何解决?
主要有两个文件:
-登陆.js
import React, { useEffect, useState, useCallback } from "react";
import CodeEditorWindow from "./CodeEditorWindow";
import axios from "axios";
import { classnames } from "../utils/general";
import { languageOptions } from "../constants/languageOptions";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import { defineTheme } from "../lib/defineTheme";
import useKeyPress from "../hooks/useKeyPress";
import OutputWindow from "./OutputWindow";
import CustomInput from "./CustomInput";
import OutputDetails from "./OutputDetails";
import ThemeDropdown from "./ThemeDropdown";
import LanguagesDropdown from "./LanguagesDropdown";
import { initializeApp } from "firebase/app";
import { getDatabase, ref,onValue } from "firebase/database";
const javascriptDefault = `/**
* Problem: Binary Search: Search a sorted array for a target value.
*/
// Time: O(log n)
const binarySearch = (arr, target) => {
return binarySearchHelper(arr, target, 0, arr.length - 1);
};
const binarySearchHelper = (arr, target, start, end) => {
if (start > end) {
return false;
}
let mid = Math.floor((start + end) / 2);
if (arr[mid] === target){
return mid;
}
if (arr[mid] < target) {
return binarySearchHelper(arr, target, mid + 1, end);
}
if (arr[mid] > target) {
return binarySearchHelper(arr, target, start, mid - 1);
}
};
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const target = 5;
console.log(binarySearch(arr, target));
`;
const Landing = () => {
const [code, setCode] = useState(javascriptDefault);
const [customInput, setCustomInput] = useState("");
const [outputDetails, setOutputDetails] = useState(null);
const [processing, setProcessing] = useState(null);
const [theme, setTheme] = useState("cobalt");
const [language, setLanguage] = useState(languageOptions[0]);
const enterPress = useKeyPress("Enter");
const ctrlPress = useKeyPress("Control");
const onSelectChange = (sl) => {
console.log("selected Option...", sl);
setLanguage(sl);
};
const firebaseConfig = {
apiKey: "xyz",
authDomain: "xyz.firebaseapp.com",
databaseURL: "https://xyz-default-rtdb.firebaseio.com",
projectId: "xyz",
storageBucket: "xyz.appspot.com",
messagingSenderId: "94230328",
appId: "1:907394230328:web:74604ad262f6decb171ecd"
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
const db = getDatabase(app);
onValue(ref(db, 'Content/' + language),(snapshot) => {
const data = snapshot.val();
if (data) {
setCode(data);
}
});
const checkStatus = useCallback(async (token) => {
const options = {
method: "GET",
url: process.env.REACT_APP_RAPID_API_URL + "/" + token,
params: { base64_encoded: "true", fields: "*" },
headers: {
"X-RapidAPI-Host": process.env.REACT_APP_RAPID_API_HOST,
"X-RapidAPI-Key": process.env.REACT_APP_RAPID_API_KEY,
},
};
try {
let response = await axios.request(options);
let statusId = response.data.status?.id;
// Processed - we have a result
if (statusId === 1 || statusId === 2) {
// still processing
setTimeout(() => {
checkStatus(token);
}, 2000);
return;
} else {
setProcessing(false);
setOutputDetails(response.data);
showSuccessToast(`Compiled Successfully!`);
console.log("response.data", response.data);
return;
}
} catch (err) {
console.log("err", err);
setProcessing(false);
showErrorToast();
}
}, []);
const handleCompile = useCallback(() => {
setProcessing(true);
const formData = {
language_id: language.id,
// encode source code in base64
source_code: btoa(code),
stdin: btoa(customInput),
};
const options = {
method: "POST",
url: process.env.REACT_APP_RAPID_API_URL,
params: { base64_encoded: "true", fields: "*" },
headers: {
"content-type": "application/json",
"Content-Type": "application/json",
"X-RapidAPI-Host": process.env.REACT_APP_RAPID_API_HOST,
"X-RapidAPI-Key": process.env.REACT_APP_RAPID_API_KEY,
},
data: formData,
};
axios
.request(options)
.then(function (response) {
console.log("res.data", response.data);
const token = response.data.token;
checkStatus(token);
})
.catch((err) => {
let error = err.response ? err.response.data : err;
// get error status
let status = err.response.status;
console.log("status", status);
if (status === 429) {
console.log("too many requests", status);
showErrorToast(
`Quota of 100 requests exceeded for the Day! Please read the blog on freeCodeCamp to learn how to setup your own RAPID API Judge0!`,
10000
);
}
setProcessing(false);
console.log("catch block...", error);
});
}, [checkStatus, code, customInput, language.id]);
useEffect(() => {
if (enterPress && ctrlPress) {
console.log("enterPress", enterPress);
console.log("ctrlPress", ctrlPress);
handleCompile();
}
}, [ctrlPress, enterPress, handleCompile]);
const onChange = (action, data) => {
switch (action) {
case "code": {
setCode(data);
break;
}
default: {
console.warn("case not handled!", action, data);
}
}
};
function handleThemeChange(th) {
const theme = th;
console.log("theme...", theme);
if (["light", "vs-dark"].includes(theme.value)) {
setTheme(theme);
} else {
defineTheme(theme.value).then((_) => setTheme(theme));
}
}
useEffect(() => {
defineTheme("oceanic-next").then((_) =>
setTheme({ value: "oceanic-next", label: "Oceanic Next" })
);
}, []);
const showSuccessToast = (msg) => {
toast.success(msg || `Compiled Successfully!`, {
position: "top-right",
autoClose: 1000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
});
};
const showErrorToast = (msg, timer) => {
toast.error(msg || `Something went wrong! Please try again.`, {
position: "top-right",
autoClose: timer ? timer : 1000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
});
};
return (
<>
<ToastContainer
position="top-right"
autoClose={2000}
hideProgressBar={false}
newestOnTop={false}
closeOnClick
rtl={false}
pauseOnFocusLoss
draggable
pauseOnHover
/>
<div className="h-4 w-full bg-gradient-to-r from-pink-500 via-red-500 to-yellow-500"></div>
<div className="flex flex-row">
<div className="px-4 py-2">
<LanguagesDropdown onSelectChange={onSelectChange} />
</div>
<div className="px-4 py-2">
<ThemeDropdown handleThemeChange={handleThemeChange} theme={theme} />
</div>
</div>
<div className="flex flex-row space-x-4 items-start px-4 py-4">
<div className="flex flex-col w-full h-full justify-start items-end">
<CodeEditorWindow
code={code}
onChange={onChange}
language={language?.value}
theme={theme.value}
/>
</div>
<div className="right-container flex flex-shrink-0 w-[30%] flex-col">
<OutputWindow outputDetails={outputDetails} />
<div className="flex flex-col items-end">
<CustomInput
customInput={customInput}
setCustomInput={setCustomInput}
/>
<button
onClick={handleCompile}
disabled={!code}
className={classnames(
"mt-4 border-2 border-black z-10 rounded-md shadow-[5px_5px_0px_0px_rgba(0,0,0)] px-4 py-2 hover:shadow transition duration-200 bg-white flex-shrink-0",
!code ? "opacity-50" : ""
)}
>
{processing ? "Processing..." : "Compile and Execute"}
</button>
</div>
{outputDetails && <OutputDetails outputDetails={outputDetails} />}
</div>
</div>
</>
);
};
export default Landing;
-CodeEditor.js
import React, { useState } from "react";
import Editor from "@monaco-editor/react";
import { initializeApp } from "firebase/app";
import { getDatabase, ref, set, get } from "firebase/database";
const firebaseConfig = {
apiKey: "xyz",
authDomain: "xyz.firebaseapp.com",
databaseURL: "https://xyz-default-rtdb.firebaseio.com",
projectId: "xyz",
storageBucket: "xyz.appspot.com",
messagingSenderId: "94230328",
appId: "1:907394230328:web:74604ad262f6decb171ecd"
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
const db = getDatabase(app);
const CodeEditorWindow = ({ onChange, language, code, theme }) => {
const [value, setValue] = useState(code || "");
const handleEditorChange = (value) => {
get(ref(db, 'Content/' + language)).then((snapshot) => {
if (snapshot.exists()) {
if(snapshot.val() !== value){
set(ref(db, 'Content/' + language), {
code: value
});
setValue(value);
onChange("code", value);
}
else{
setValue(value);
onChange("not", value);
}
} else {
set(ref(db, 'Content/' + language), {
code: value
});
setValue(value);
onChange("code", value);
}
}).catch((error) => {
console.error(error);
});
};
return (
<div className="overlay rounded-md overflow-hidden w-full h-full shadow-4xl">
<Editor
height="85vh"
width={`100%`}
language={language || "javascript"}
value={value}
theme={theme}
defaultValue="// some comment"
onChange={handleEditorChange}
/>
</div>
);
};
export default CodeEditorWindow;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.