Skip to content

React Around Collections

Framework

  • nextjs
  • remix
  • Astro Astro powers the world's fastest websites, client-side web apps, dynamic API endpoints, and everything in-between.

重构、项目架构

State Manage

实现:

点击查看代码
ts
import { useSyncExternalStore } from 'react'

const createStore = (createState) => {
  let state
  const listeners = new Set()

  const setState = (partial, replace) => {
    const nextState = typeof partial === 'function' ? partial(state) : partial

    if (!Object.is(nextState, state)) {
      const previousState = state

      if (!replace) {
        state =
          typeof nextState !== 'object' || nextState === null
            ? nextState
            : Object.assign({}, state, nextState)
      } else {
        state = nextState
      }
      listeners.forEach((listener) => listener(state, previousState))
    }
  }

  const getState = () => state

  const subscribe = (listener) => {
    listeners.add(listener)
    return () => listeners.delete(listener)
  }

  const destroy = () => {
    listeners.clear()
  }

  const api = { setState, getState, subscribe, destroy }

  state = createState(setState, getState, api)

  return api
}

function useStore(api, selector) {
  function getState() {
    return selector(api.getState())
  }

  return useSyncExternalStore(api.subscribe, getState)
}

export const create = (createState) => {
  const api = createStore(createState)

  const useBoundStore = (selector) => useStore(api, selector)

  Object.assign(useBoundStore, api)

  return useBoundStore
}
official start example
ts
import { createMachine, createActor, assign } from 'xstate'

// State machine
const toggleMachine = createMachine({
  id: 'toggle',
  initial: 'inactive',
  context: {
    count: 0
  },
  states: {
    inactive: {
      on: {
        TOGGLE: { target: 'active' }
      }
    },
    active: {
      entry: assign({ count: ({ context }) => context.count + 1 }),
      on: {
        TOGGLE: { target: 'inactive' }
      }
    }
  }
})

// Actor (instance of the machine logic, like a store)
const toggleActor = createActor(toggleMachine)
toggleActor.subscribe((state) => console.log(state.value, state.context))
toggleActor.start()
// => logs 'inactive', { count: 0 }

toggleActor.send({ type: 'TOGGLE' })
// => logs 'active', { count: 1 }

toggleActor.send({ type: 'TOGGLE' })
// => logs 'inactive', { count: 1 }
Xstate实现红绿灯有限状态机
ts
import { createMachine, createActor } from 'xstate'

const lightMachine = createMachine({
  id: 'light',
  initial: 'red',
  states: {
    red: {
      on: {
        TRANS: 'green'
      }
    },
    green: {
      on: {
        TRANS: 'yellow'
      }
    },
    yellow: {
      on: {
        TRANS: 'red'
      }
    }
  }
})

const lightService = createActor(lightMachine).start()

lightService.subscribe((state) => {
  console.log(state.value)
})

// 发送事件
lightService.send('TRANS') // 'green'
lightService.send('TRANS') // 'yellow'
lightService.send('TRANS') // 'red'

// 批量发送事件
lightService.send({ type: 'TRANS' }) // 单个事件
lightService.send({ type: 'TRANS' }) // 单个事件

// 终止状态机
lightService.stop()

server api state

CSS

UI library

动画

RN

project

  • Turbopack
  • Bit.dev Bit.dev是一种快速、动态化、协同式构建团队组件库的解决方案

Articles

核心:React入官网所述,只是一个构建UI的库,但对一个复杂的React Application来说,如何构建,处理却没有很好的说明,当然不止是react,下面只是结合React展开,其实对于一个前端应用来说都可以复用这些思想。

如何组织代码,组装,存放计算/业务,数据交互/联动等逻辑,大概就是根据不同的关注点,划分到不同的文件/夹结构,view-model-data的分层设计,而不是在组件/hooks中搞定一切

Single Component Application

Multiple Component Application

问题: there are things like sending network requests, converting data into different shapes for the view to consume, and collecting data to send back to the server. And having this code inside components doesn’t feel right as they’re not really about user interfaces. Also, some components have too many internal states.

State management with hooks

使用自定义hooks抽取这些逻辑到单独的地方,The only problem is that in hooks, apart from the side effect and state management, some logic doesn’t seem to belong to the state management but pure calculations.

Business models emerged

Layered frontend application

It’s good practice to split view and non-view code into separate places. The reason is, in general, views are changing more frequently than non-view logic. Also, as they deal with different aspects of the application, separating them allows you to focus on a particular self-contained module that is much more manageable when implementing new features.

In case I don't see you. Good afternoon, good evening, and good night.