Skip to content

State

引言

当创建好AutoStore实例后就可以存取状态。

  • 使用useReactive

用来在组件中访问和更新Store的状态数据,更新时会导致重新渲染。

  • 直接读写store.state

store.state返回的是一个响应式对象reactive,其实质是通过Proxy实现的。 当读写store.state时,会触发内部的依赖收集,相关计算属性的运行,配合signal机制可以自动触发组件的细粒度重新渲染。

useReactive

Store对象提供了useReactive方法,用来在组件中访问和更新Store的状态数据。

函数签名

ts
type UseStateResult<Value,State extends Dict>=[Value extends Dict ? ComputedState<Value> : Value,(value:Value | ((state:ComputedState<State>)=>void))=>void]
type UseStateGetter<Value,State extends Dict>= (state:ComputedState<State>)=>Value
type UseStateSetter<SetValue,State extends Dict>= (value:SetValue,state:ComputedState<State>)=>void


interface UseStateType<State extends Dict> {
    <Value=any>(selector: string): UseStateResult<Value,State>
    <Value=any>(selector: string[]): UseStateResult<Value,State>
    <Value=any>(selector: string,async:boolean): UseStateResult<AsyncComputedValue<Value>,State>
    <Value=any>(selector: string[],async:boolean): UseStateResult<AsyncComputedValue<Value>,State>
    <Value=any,SetValue=any>(getter: UseStateGetter<Value,State>,setter?:UseStateSetter<SetValue,State>): UseStateResult<Value,State>
    (): UseStateResult<State,State>
}

基础使用

其使用方式与ReactuseState方法类似,返回一个statesetState的元组。

tsx
import { 
createStore
} from "@autostorejs/react"
const {
state
,
useReactive
,
$
} =
createStore
({
user
:{
firstName
:"Zhang",
lastName
:"Fisher",
age
:18,
} }) // 使用方式1 const [
age
,
setAge
] =
useReactive
('user.age')
// 使用方式2 const [
firstName
,
setFirstName
] =
useReactive
(['user','firstName'])

简单示例如下:

WARNING

当更新Age时会重新渲染整个组件,其行为与ReactuseState类似。

getter & setter

useReactive还可以接受gettersetter两个函数参数,用来获取和设置State中的组合属性。

  • getter:用来获取State中的组合属性。
  • setter:用来设置State中的组合属性。
tsx
 
const { useReactive,state,$ } = createStore( {
  firstName:"Zhang",
  lastName:"Fisher",
  fullName:(state)=>state.firstName+state.lastName,
})

const [fullName,setFullName] = useReactive<string,[string,string]>(
    (state)=>state.fullName,       // getter
    ([first,last],state)=>{        // setter
      state.firstName=first
      state.lastName=last
    }
)

// 修改firstName和lastName
setFullName(["Hello","Voerkai18n❤️"]) 

提示

useReactive<string,[string,string]>可以指定gettersetter的泛型类型,这样在使用时会有更好的代码提示。

简单示例如下:

提示

useReactive还有一个别名useState,但是由于useStateReact内置名称相同,使用时经常需要重命名,所以在AutoStore中使用useReactive来代替。

直接读写

除了使用useReactive方法读写状态外,sotre.state返回的是一个响应式Proxy对象,可以直接读写也会触发内部的依赖收集和事件响应。

ts
const { state , $ } = createStore({
  age:18
})

// 直接更新Age也会触发响应和依赖收集,但是不会触发重新渲染整个组件
state.age=100

特殊注意:

  • 直接修改状态state.age=100会触发内部的依赖收集和事件响应,但是不会触发重新渲染整个组件。因为state是一个响应式对象(即经过proxy处理过的对象),对其的读写会触发内部的依赖收集和事件响应。但是并没有通知React组件,所以不会触发组件的重新渲染。
  • 如果要让直接读写状态时触发重新渲染,就需要对state进行包装,让状态变化时通知React组件重新渲染。这需要使用:
    • 使用useReactive
    • 使用signal信号组件

无论是使用useReactive信号组件均原理均是会拦截state读写事件,然后通知React组件重新渲染。

简单演示如下:

WARNING

此例中更新Age时并不会重新渲染整个组件,而只会渲染$('age'),这就是信号组件的功能,其可以提供细粒度的更新渲染。 $('age')本质上返回的是一个经过React.memo包装的ReactNode

useAsyncReactive

如果状态是一个异步计属性,也可以使用useAsyncReactive来处理。

详见异步计算属性

小结

  • 更新Store的状态可以不需要使用useReactive返回的setXXXXX,直接使用state.xxxx=xxx即可更新状态触发响应。
  • 如果要提供细粒度的更新,可以使用signal机制,通过$方法创建一个信号组件,用来触发局部更新。