[rukawa]换种心情处理数据流(一)

351 阅读4分钟

背景(轻喷)

在我的日常开发中,至少80%的数据都有明确的消费者(全局的数据除外,比如用户信息,我也不知道啥时候会被谁用到),而且大多数数据都会具有时效性(使用完一次之后就没用了)。

最简单的例子就是表单查询,查询的信息在拉取到想要的接口信息后,一般来说就没用了。但是在实际的开发中,我们会被迫地去保存这个值,因为查询组件表格组件可能不在一个文件(组件)中,我没法直接把我的searchValue传递给table,我真的受够了因此带来的困扰,要设计props, onValueChange,还要把状态提升到父组件,或者去写个context去解决这个明明看起来很简单的数据传递。

为什么 table 不能去直接订阅 search 的值呢,所以就有了 rukawa 这个不成熟的构想,将有订阅关系的数据节点都保存在一个集合中,数据节点可以订阅其他节点的值,并在订阅的节点发生valueChange时收到最新的values;

图画得有些抽象。

image.png

前言

其实很早就想做个尝试了,一直拖了很久,结果 灌篮高手,4月20就要上映了,再拖就没有脸去看流卡瓦暴打(???)泽北了,yep,rukawa 就是指流川枫。

希望它能像流川枫一样,虽然特立独行,但是还是能凭借强大的个人能力帮助整个项目。

使用

平平无奇的使用方式。

$ npm install rukawa  
import { useRukawa } from 'rukawa';  
  
const {  
  rukawaValues,  
  setRukawaValue  
} = useRukawa({  
  name: 'test',  
  subscribes: [  
    'test-1'  
  ],  
  initialValue: ''  
})  

提供一个 useRukawahook,可以从中导出 rukawaValuessetRukawaValue,
rukawaValues 是订阅的节点的 values 集合, setRukawaValue 是更改当前节点的值,
更改后,订阅该值的节点中的 rukawaValues, 会获取到最新的值。

example

image.png

一个简单的测试页面,点击操作会弹一个modal

如果我把他们分为3个组件,[search ,table, modal],就必须要考虑数据怎么相互传递的问题,从 search 中怎么把 value 传递给 table 获取列表信息,然后 table 怎么把点击列的数据传递给 modal 进行展示等等。一般来说,就会用到 context 或者在父组件定义状态,俗称 状态提升

就像前面说的, search 中的 value 明明用过一次以后就没用了,为啥我还要傻傻地给它保存起来呢,相同的逻辑也存在于 tablemodal 中,这就是我认为的时效性较强的数据,这种数据的保存起来并没有什么意义,还不如直接通信,没有中间商赚差价。

(如果不想代码直接变一坨屎的话,建议日常开发中,多定义下常量,这里我把几个有订阅关系的组件name都定义了常量,也方便以后找哪些有订阅关系)

search component

export const Search = () => {  
  // 注册 node, 拿到 setRukawaValue  
  const { setRukawaValue } = useRukawa({  
    name: RUKAWA_SEARCH_CONST.SEARCH,  
    initialValue:''  
  })  
  
  const [val, setVal] = useState('');  
  
  return (  
    <div>  
      <Input  
        style={{ width: '200px', marginRight: '16px' }}  
        onChange={e => setVal(e.target.value)}  
      />  
     <Button  
       type="primary"  
       onClick={() => {   
         setRukawaValue(val);  
       }}  
     >查询</Button>  
    </div>  
  )  
}

table component

export const TableComponent = () => {  
  const {  
    rukawaValues,  
    setRukawaValue  
  } = useRukawa({  
    name: RUKAWA_SEARCH_CONST.TABLE,  
    // 注册节点,并订阅 search 中的值
    subscribes: [  
      RUKAWA_SEARCH_CONST.SEARCH  
    ],  
    initialValue: ''  
  })  
  const [data, setData] = useState<any[]>([]);  
  
  // 模拟 rukawaValues 变更重新获取列表数据
  useEffect(() => {  
    const value = rukawaValues[RUKAWA_SEARCH_CONST.SEARCH];  
    if (value) {  
      setData([{  
        key: value,  
        name: value  
      }])  
    }  
  }, [rukawaValues])  
  
  const columns = [  
    {  
      title: '姓名',  
      dataIndex: 'name',  
      key: 'name',  
    },  
    {  
      title: '操作',  
      key: 'name',  
      render: (_: any, record: any) => (  
        // 修改自己的 node value,触发 modal 中 value 的更新
        <a onClick={() => setRukawaValue(record.name)}>操作</a>  
      ),  
    }  
  ];  
  
  return (  
    <div style={{ marginTop: '32px' }}>  
      <Table bordered dataSource={data} columns={columns} />  
    </div>  
  )  
}

search 中点击查询后, value 将直接被 table 获取,触发查询列表的操作,同理 table 中点击操作,会把 value 传递给 modal 触发展示,这里就不展示代码了。

结语

虽然有这个想法很久了,但是真正开始写其实也就没多久,所以功能上很不成熟,只能说基本实现了我最初的构想,而且这种直接订阅的数据流方案,可能并不会被认可,但是它确实能让我写代码时候避免那些令我无语的 状态提升公共状态定义

但是,就算不被认可,应该也会先努力迭代下去吧,自己的项目用一用应该死不了人。就像打海南时候,就算大家觉得流川枫独,不认可他的球风,哥们还是半场拿下29分,在赤木受伤的情况下扳平了比分~

后续迭代

尽量保证在4.20前能更新出一个令自己满意的版本,然后开开心心去看电影。

  1. 测试用例补一补
  2. 初始值的处理需要更加优雅一点,因为现在获取 value 必须在节点创建以后,节点创建的时间先后问题,会导致拿不到设定的初始值
  3. 增加 options 提供加强功能,比如防抖啥的。
  4. 可以便捷地查看当前的订阅关系