Skip to main content

Function Standards

This document establishes coding standards for functions in the OX Agry enterprise agricultural application. Following these guidelines ensures consistency, maintainability, and optimal performance across the codebase.

Table of Contents

  1. Function Types
  2. Export Patterns
  3. Component Organization
  4. Best Practices
  5. Code Examples

Function Types

Arrow Functions

Arrow functions maintain lexical this binding and provide concise syntax for simple functions.

Use CaseRecommendationExample
Functional Components✅ Preferredconst CropCard = ({ crop }) => { ... }
Event Handlers✅ Preferredconst handleSubmit = (e) => { ... }
Component-internal Functions✅ Preferredconst calculateTotal = () => { ... }
useCallback Wrappers✅ Requiredconst memoizedFn = useCallback(() => { ... }, [])

Regular Functions

Regular functions provide better readability for complex logic and support hoisting.

Use CaseRecommendationExample
Pure Utility Functions✅ Preferredfunction calculateYield(area, efficiency) { ... }
Custom Hooks✅ Requiredfunction useFieldData(fieldId) { ... }
Complex Logic✅ Preferredfunction optimizeCropRotation(fields) { ... }
Generator Functions✅ Requiredfunction* paginate(items) { ... }

Export Patterns

Export TypeWhen to UseSyntaxImport Syntax
Named Function ExportUtility functions, hooksexport function calculateArea() {}import { calculateArea } from './utils'
Named Arrow FunctionComponents, simple utilitiesexport const formatDate = () => {}import { formatDate } from './formatters'
Default ExportMain page componentsexport default function Page() {}import Page from './Page'
Multiple ExportsRelated functionalityMultiple named exports in one fileimport { fn1, fn2 } from './module'

Component Organization

Functional Component Structure

Follow this order for organizing code within components:

  1. Imports
  2. Type definitions
  3. Component function declaration
  4. Hooks (useState, useEffect, etc.)
  5. Event handlers
  6. Derived/computed values
  7. Helper functions
  8. Render logic (return statement)
import React, { useState } from "react";
import { formatData } from "./utils";

// Type definitions
interface CropProps {
id: string;
name: string;
}

// Component declaration
export const CropItem = ({ id, name }: CropProps) => {
// Hooks
const [expanded, setExpanded] = useState(false);

// Event handlers
const handleToggle = () => {
setExpanded((prev) => !prev);
};

// Helper functions
const renderDetails = () => {
if (!expanded) return null;
return <div className="details">...</div>;
};

// Render logic
return (
<div className="crop-item">
<h3>{name}</h3>
<button onClick={handleToggle}>
{expanded ? "Hide" : "Show"} Details
</button>
{renderDetails()}
</div>
);
};

Best Practices

Naming Conventions

  • Components: PascalCase (CropViewer, FieldMap)
  • Hooks: camelCase with 'use' prefix (useWeatherData, useFieldSelection)
  • Event Handlers: camelCase with 'handle' prefix (handleSubmit, handleCropSelect)
  • Utility Functions: camelCase, descriptive verbs (calculateYield, formatDate)

Performance Optimization

  • Use useCallback for functions passed as props to prevent unnecessary re-renders
  • Use useMemo for expensive calculations
  • Extract pure utility functions outside of components

Function Parameters

  • Use object destructuring for multiple parameters
  • Use TypeScript interfaces for complex parameter types
  • Provide default values where appropriate

Default Export Pattern

For default exports, we will standardize on the inline export pattern for consistency:

// Recommended: Inline default export function
export default function FieldDashboard({ fieldId }: Props) {
// Implementation
return <div>Dashboard for field {fieldId}</div>;
}

This approach offers several advantages:

  • Cleaner, more concise syntax
  • Immediate identification of the exported component/function
  • Better support in some code editors for navigation
  • Consistent pattern that's easy for all developers to follow

For React components specifically, use:

export default function ComponentName(props: ComponentProps) {
// Component implementation
}

For utility functions that need to be the default export:

export default function utilityName(param1: Type, param2: Type): ReturnType {
// Implementation
}

Important: Default exports should primarily be used for:

  1. Page components that represent a full route
  2. Main feature components that are the primary export of a file
  3. Configuration objects or specialized functions that are the primary purpose of a file

Code Examples

Component with Event Handlers

export const FieldSelector = ({ fields, onSelect }: FieldSelectorProps) => {
const handleFieldClick = (fieldId: string) => {
onSelect(fieldId);
};

return (
<div className="field-selector">
{fields.map((field) => (
<button key={field.id} onClick={() => handleFieldClick(field.id)}>
{field.name}
</button>
))}
</div>
);
};

Custom Hook

export function useCropData(cropId: string) {
const [data, setData] = useState<CropData | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);

useEffect(() => {
if (!cropId) return;

setLoading(true);
fetchCropData(cropId)
.then((result) => setData(result))
.catch((err) => setError(err))
.finally(() => setLoading(false));
}, [cropId]);

return { data, loading, error };
}

Utility Functions

// lib/agricultural-utils.ts

export function calculateFieldArea(length: number, width: number): number {
return length * width;
}

export function convertToAcres(hectares: number): number {
return hectares * 2.47105;
}

export function formatArea(area: number, unit: "ha" | "acre"): string {
return `${area.toFixed(2)} ${unit}`;
}

Performance Optimized Component

export const CropAnalytics = ({ cropId, historical }: CropAnalyticsProps) => {
// Memoized data processing function
const processData = useCallback(
(rawData: RawCropData) => {
// Complex data transformation logic
return transformedData;
},
[
/* dependencies */
]
);

// Memoized derived value
const summaryStats = useMemo(() => {
if (!cropData) return null;
return calculateSummaryStatistics(cropData);
}, [cropData]);

return <div className="analytics-container">{/* Component rendering */}</div>;
};