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
Markdown
# 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.