Skip to content

azot-dev/cortex

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Cortex Logo

A React framework for building efficient and scalable applications

npm version build state monthly downloads

Cortex

The full documentation is available here.

Overview

React is a library, not a framework. Cortex brings the missing architectural layer to structure your app, test business logic easily, and keep your codebase scalable, using object-oriented services and a reactive state powered by Valtio.

  • Share code between React and React Native (or any JS framework)
  • Test business logic directly with Jest (no UI required)
  • TDD-friendly development
  • Clean architecture (ports/adapters) with single-responsibility services

Installation

npm i @azot-dev/cortex

React is a peerDependency. Valtio is bundled by the library.

CLI template (recommended)

Generate a ready-to-use skeleton inside your React project:

npx @azot-dev/cortex@latest init react

Generated structure:

cortex/
  dependencies/
    _dependencies.ts
  services/
    _services.ts
    counter.service.ts
    logger.service.ts
  setup/
    base.service.ts
    setup.ts

React provider

import { CortexProvider } from '@azot-dev/cortex'
import { createCore } from './cortex/setup/setup'

export function Root() {
  const core = createCore()
  return (
    <CortexProvider core={core}>
      <App />
    </CortexProvider>
  )
}

Services and state

Services extend a base (BaseService) and hold a state object automatically made reactive via Valtio. Access other services with this.getService('name') and dependencies via this.dependencies.

// counter.service.ts
import { Service } from './cortex/setup/base.service'

type State = { count: number }

export class CounterService extends Service<State> {
  state: State = { count: 0 }

  increment() {
    this.state.count++
    this.getService('logger').log(`counter incremented: ${this.state.count}`)
  }

  decrement() {
    if (this.state.count > 0) this.state.count--
  }
}

Typed hook to consume a service in React:

// from the template
import { useService } from './cortex/setup/setup'

export function CounterButton() {
  const counter = useService('counter') // exposes public methods + reactive state
  return <button onClick={counter.increment}>{counter.count}</button>
}

Optional initialization method executed after the core is instantiated:

export class LoggerService extends Service<{ logs: string[] }> {
  state = { logs: [] }

  init() {
    this.log('Logger initialized')
  }

  log(message: string) {
    this.state.logs.push(message)
    console.log(message)
  }
}

Async hook

The library exposes a simple helper hook:

import { useAsync } from '@azot-dev/cortex'
import { useService } from './cortex/setup/setup'

export function Shoes() {
  const api = useService('shoes')
  const { data, loading, error, refetch } = useAsync(api.load, { lazy: false })
  if (loading) return <span>Loading…</span>
  if (error) return <span>Error</span>
  return <div>{JSON.stringify(data)}</div>
}

Unit tests

Test service logic directly with Jest:

import { createCore } from './cortex/setup/setup'

describe('counter', () => {
  it('increments', () => {
    const core = createCore()
    const counter = core.getService('counter')
    expect(counter.state.count).toBe(0)
    counter.increment()
    expect(counter.state.count).toBe(1)
  })
})

About

The missing brick of React for TDD and clean architecture

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •