UNPKG

react-text-editor-kit

Version:

React Text Editor Kit is a customizable rich text editor component for React applications. It provides a flexible and easy-to-use interface for users to create and edit content with various formatting options. And also easy to integrate in react applicati

336 lines (275 loc) 9.21 kB
# Backend Function Integration Methods This document explains different methods to fetch functions from the backend and store them in state for use in your React frontend. ## Overview Your current implementation already shows one pattern for fetching backend functions. Here are several comprehensive approaches you can use: ## Method 1: Using Custom Hooks (Recommended) ### Multiple Functions Hook ```javascript import { useBackendFunctions } from "./hooks/useBackendFunctions"; const MyComponent = ({ apiKey }) => { const { functions, isLoading, error, executeFunction, hasFunction, isInitialized, } = useBackendFunctions(apiKey, "http://your-api.com/functions"); const handleClick = () => { if (hasFunction("myFunction")) { const result = executeFunction("myFunction", "param1", "param2"); console.log(result); } }; return ( <div> {isLoading && <p>Loading functions...</p>} {error && <p>Error: {error}</p>} <button onClick={handleClick}>Execute Function</button> </div> ); }; ``` ### Single Function Hook ```javascript import { useBackendFunction } from "./hooks/useBackendFunctions"; const MyComponent = ({ apiKey }) => { const { function: myFunction, isLoading, error, executeFunction, isLoaded, } = useBackendFunction( apiKey, "http://your-api.com/functions", "handleInput" ); return ( <div> {isLoading && <p>Loading function...</p>} {error && <p>Error: {error}</p>} <button onClick={() => executeFunction("parameter")} disabled={!isLoaded}> Execute Function </button> </div> ); }; ``` ## Method 2: Manual Implementation (Your Current Approach) ```javascript import { useState, useEffect } from "react"; import { invokeApi } from "./bl_libs/invokeApi"; const MyComponent = ({ apiKey }) => { const [functionsObject, setFunctionsObject] = useState(null); const fetchFunctions = async () => { try { const response = await invokeApi({ path: "http://your-api.com/functions", method: "GET", headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", }, }); if (response && response.functions) { // Convert function string to executable function const addFn = new Function(response.functions.handleInput); setFunctionsObject(addFn); } } catch (error) { console.error("Error fetching functions:", error); } }; useEffect(() => { fetchFunctions(); }, [apiKey]); useEffect(() => { if (functionsObject) { // Execute the function const result = functionsObject(); console.log("Function executed:", result); } }, [functionsObject]); return <div>Your component content</div>; }; ``` ## Method 3: State-Based Function Storage ```javascript import { useState, useEffect } from "react"; import { invokeApi } from "./bl_libs/invokeApi"; const MyComponent = ({ apiKey }) => { const [customFunctions, setCustomFunctions] = useState({}); const [isLoading, setIsLoading] = useState(false); const fetchCustomFunctions = async () => { setIsLoading(true); try { const response = await invokeApi({ path: "http://your-api.com/custom-functions", method: "GET", headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", }, }); if (response && response.functions) { const functions = {}; Object.keys(response.functions).forEach((key) => { try { const funcString = response.functions[key]; // Method 1: Using new Function() constructor functions[key] = new Function("return " + funcString)(); // Method 2: Using eval() (less secure) // functions[key] = eval('(' + funcString + ')'); } catch (err) { console.error(`Error creating function ${key}:`, err); } }); setCustomFunctions(functions); } } catch (error) { console.error("Error fetching functions:", error); } finally { setIsLoading(false); } }; const executeCustomFunction = (functionName, ...args) => { if (customFunctions[functionName]) { return customFunctions[functionName](...args); } else { console.error(`Function ${functionName} not available`); return null; } }; useEffect(() => { fetchCustomFunctions(); }, [apiKey]); return ( <div> {isLoading && <p>Loading functions...</p>} {Object.keys(customFunctions).map((funcName) => ( <button key={funcName} onClick={() => executeCustomFunction(funcName)}> Execute {funcName} </button> ))} </div> ); }; ``` ## Method 4: Dynamic Function Creation ```javascript const createDynamicFunction = (functionString, parameters = {}) => { try { // Create a function that accepts parameters const dynamicFunction = new Function( "params", `return (${functionString})(params)` ); return dynamicFunction; } catch (err) { console.error("Error creating dynamic function:", err); return null; } }; // Usage const dynamicFunc = createDynamicFunction( '(params) => { console.log("Dynamic function called with:", params); return params.value * 2; }', { value: 5 } ); if (dynamicFunc) { const result = dynamicFunc({ value: 10 }); console.log("Result:", result); // Output: 20 } ``` ## Method 5: Function with useEffect Execution ```javascript import { useState, useEffect } from "react"; import { invokeApi } from "./bl_libs/invokeApi"; const MyComponent = ({ apiKey }) => { const [storedFunction, setStoredFunction] = useState(null); const fetchAndStoreFunction = async () => { try { const response = await invokeApi({ path: "http://your-api.com/function/handleInput", method: "GET", headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", }, }); if (response && response.function) { // Store the function in state const func = new Function("return " + response.function)(); setStoredFunction(func); } } catch (err) { console.error("Error fetching function:", err); } }; // Execute stored function when it changes useEffect(() => { if (storedFunction) { // Execute the function with any required parameters const result = storedFunction(); console.log("Stored function executed:", result); } }, [storedFunction]); useEffect(() => { fetchAndStoreFunction(); }, [apiKey]); return <div>Your component content</div>; }; ``` ## Backend API Response Format Your backend should return functions in this format: ```json { "functions": { "handleInput": "function(content) { return { modifiedContent: content.toUpperCase() }; }", "formatText": "function(text) { return text.replace(/\\s+/g, ' ').trim(); }", "autoSave": "function(data) { console.log('Auto-saving:', data); return { success: true }; }" } } ``` Or for a single function: ```json { "function": "function(content) { return { modifiedContent: content.toUpperCase() }; }" } ``` ## Security Considerations 1. **Function Validation**: Always validate function strings before execution 2. **Sandboxing**: Consider using a sandboxed environment for function execution 3. **Authentication**: Ensure proper API authentication 4. **Error Handling**: Implement comprehensive error handling ## Best Practices 1. **Use Custom Hooks**: For reusable logic across components 2. **Error Handling**: Always handle errors gracefully 3. **Loading States**: Show loading indicators while fetching functions 4. **Type Safety**: Consider using TypeScript for better type safety 5. **Testing**: Write tests for your function integration logic ## Integration with Your Current Code To integrate with your existing `ReactEditorKit.jsx`: ```javascript // In your ReactEditorKit component const { functions, executeFunction, hasFunction } = useBackendFunctions( apiKey, "http://192.168.1.72:8080/api/editor-functions" ); // Use in your existing CheckAccess function const CheckAccess = async (apiKey) => { // Your existing logic... // Execute backend function if available if (hasFunction("handleInput")) { const result = executeFunction("handleInput", { content: editorRef.current?.innerHTML, timestamp: Date.now(), }); if (result && result.modifiedContent) { // Apply modifications editorRef.current.innerHTML = result.modifiedContent; } } }; ``` This approach gives you flexibility to choose the method that best fits your specific use case while maintaining clean, maintainable code.