Skip to main content
The SelectedPatientContext maintains the state of the currently selected patient, allowing different parts of the application to access and update the selected patient seamlessly.

Provider

SelectedPatientProvider

Wraps your application to provide patient selection state to all child components.
children
React.ReactNode
required
The components that will have access to patient context
App.tsx
import { SelectedPatientProvider } from './contexts/SelectedPatientContext';

function App() {
  return (
    <SelectedPatientProvider>
      <YourApp />
    </SelectedPatientProvider>
  );
}

Hook

useSelectedPatient()

Access the selected patient state and setter from any component within the SelectedPatientProvider.
PatientProfile.tsx
import { useSelectedPatient } from './contexts/SelectedPatientContext';

export function PatientProfile() {
  const { selectedPatient, setSelectedPatient } = useSelectedPatient();

  if (!selectedPatient) {
    return <div>No patient selected</div>;
  }

  return (
    <div>
      <h1>{selectedPatient.nombres} {selectedPatient.apellidos}</h1>
      <p>Email: {selectedPatient.email}</p>
      <button onClick={() => setSelectedPatient(null)}>
        Clear Selection
      </button>
    </div>
  );
}

Context values

selectedPatient
Patient | null
The currently selected patient object from the tcPacientes table, or null if no patient is selected.
setSelectedPatient
(patient: Patient | null) => void
Updates the currently selected patient. Pass null to clear the selection.

TypeScript types

SelectedPatientContextType

interface SelectedPatientContextType {
  selectedPatient: Patient | null;
  setSelectedPatient: (patient: Patient | null) => void;
}

Patient

type Patient = Database['public']['Tables']['tcPacientes']['Row'];

// Expanded:
interface Patient {
  id: string;
  nombres: string;
  apellidos: string;
  email: string;
  telefono: string | null;
  fechanacimiento: string;
  sexo: string;
  created_at: string;
  updated_at: string;
  // ... additional fields from tcPacientes table
}

Usage examples

Patient list with selection

PatientList.tsx
import { useSelectedPatient } from './contexts/SelectedPatientContext';
import { useState, useEffect } from 'react';
import { api } from './lib/api';

export function PatientList() {
  const { selectedPatient, setSelectedPatient } = useSelectedPatient();
  const [patients, setPatients] = useState([]);

  useEffect(() => {
    async function loadPatients() {
      const data = await api.patients.getAll();
      setPatients(data);
    }
    loadPatients();
  }, []);

  return (
    <div>
      <h2>Patients</h2>
      <ul>
        {patients.map((patient) => (
          <li
            key={patient.id}
            onClick={() => setSelectedPatient(patient)}
            style={{
              fontWeight: selectedPatient?.id === patient.id ? 'bold' : 'normal',
            }}
          >
            {patient.nombres} {patient.apellidos}
          </li>
        ))}
      </ul>
    </div>
  );
}

Conditional rendering based on selection

ClinicalHistory.tsx
import { useSelectedPatient } from './contexts/SelectedPatientContext';

export function ClinicalHistory() {
  const { selectedPatient } = useSelectedPatient();

  if (!selectedPatient) {
    return (
      <div>
        <p>Please select a patient to view their clinical history</p>
      </div>
    );
  }

  return (
    <div>
      <h1>Clinical History</h1>
      <h2>
        {selectedPatient.nombres} {selectedPatient.apellidos}
      </h2>
      {/* Display clinical history */}
    </div>
  );
}

Creating records for selected patient

VitalSigns.tsx
import { useSelectedPatient } from './contexts/SelectedPatientContext';
import { useState } from 'react';
import { api } from './lib/api';

export function VitalSigns() {
  const { selectedPatient } = useSelectedPatient();
  const [bloodPressure, setBloodPressure] = useState('');
  const [heartRate, setHeartRate] = useState('');

  if (!selectedPatient) {
    return <div>No patient selected</div>;
  }

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    
    await api.vitalSigns.create({
      paciente_id: selectedPatient.id,
      presion_arterial: bloodPressure,
      frecuencia_cardiaca: heartRate,
      fecha: new Date().toISOString(),
    });

    // Reset form
    setBloodPressure('');
    setHeartRate('');
  };

  return (
    <form onSubmit={handleSubmit}>
      <h2>Vital Signs for {selectedPatient.nombres}</h2>
      
      <label>
        Blood Pressure:
        <input
          value={bloodPressure}
          onChange={(e) => setBloodPressure(e.target.value)}
          required
        />
      </label>

      <label>
        Heart Rate:
        <input
          value={heartRate}
          onChange={(e) => setHeartRate(e.target.value)}
          required
        />
      </label>

      <button type="submit">Save</button>
    </form>
  );
}
PatientCard.tsx
import { useSelectedPatient } from './contexts/SelectedPatientContext';
import { useNavigate } from 'react-router-dom';

interface PatientCardProps {
  patient: Patient;
}

export function PatientCard({ patient }: PatientCardProps) {
  const { setSelectedPatient } = useSelectedPatient();
  const navigate = useNavigate();

  const handleViewDetails = () => {
    setSelectedPatient(patient);
    navigate('/patient-details');
  };

  return (
    <div className="patient-card">
      <h3>{patient.nombres} {patient.apellidos}</h3>
      <p>{patient.email}</p>
      <button onClick={handleViewDetails}>View Details</button>
    </div>
  );
}

Clearing selection

PatientHeader.tsx
import { useSelectedPatient } from './contexts/SelectedPatientContext';
import { useNavigate } from 'react-router-dom';

export function PatientHeader() {
  const { selectedPatient, setSelectedPatient } = useSelectedPatient();
  const navigate = useNavigate();

  if (!selectedPatient) return null;

  const handleClearSelection = () => {
    setSelectedPatient(null);
    navigate('/patients');
  };

  return (
    <div className="patient-header">
      <h2>{selectedPatient.nombres} {selectedPatient.apellidos}</h2>
      <button onClick={handleClearSelection}>Back to Patient List</button>
    </div>
  );
}

Implementation details

State management

The context uses React’s useState to manage the selected patient. When a patient is selected, all components using the useSelectedPatient hook will re-render with the new patient data.

Performance

The context value is memoized using useMemo to prevent unnecessary re-renders of child components:
const contextValue = useMemo(() => ({
  selectedPatient,
  setSelectedPatient
}), [selectedPatient]);

Common patterns

Guard against no selection:
const { selectedPatient } = useSelectedPatient();

if (!selectedPatient) {
  return <NoPatientSelected />;
}

// Safe to use selectedPatient here
Persist across routes: The selected patient persists as you navigate between routes, making it ideal for multi-page patient workflows (clinical history, prescriptions, vital signs, etc.). Clear on logout:
import { useAuth } from './contexts/AuthContext';
import { useSelectedPatient } from './contexts/SelectedPatientContext';
import { useEffect } from 'react';

export function App() {
  const { user } = useAuth();
  const { setSelectedPatient } = useSelectedPatient();

  useEffect(() => {
    if (!user) {
      // Clear patient selection when user logs out
      setSelectedPatient(null);
    }
  }, [user, setSelectedPatient]);

  return <YourApp />;
}

Build docs developers (and LLMs) love