V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
chenliangngng
V2EX  ›  前端开发

请教大佬,把一段代码用函数式编程变得更加优雅

  •  
  •   chenliangngng · 2022-04-14 22:30:26 +08:00 · 1852 次点击
    这是一个创建于 961 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近在学函数式编程,总总不能体会它的好处,而且看了几个礼拜,还没有产出一行可以上生产的代码,所以想用最日常的过程式的代码,请教下各位大佬,看看如何优化

    // import {message} from 'antd'
    // import {fetchApi} from '@/api'
    // import moment from 'moment'
    
    // const [detail, setDetail] = React.useState()
    
    const validator = async () => {
    	// do something
    }
    
    const getDetail = async (params) => {
    	await validator();
    	try{
        	const res = await fetchApi({name: 'name', ...params, id: 1})
            if (res.code >= 200 && res.code < 400) {
            	const {list, obj} = res.data
                const {date1, num1 = 1, num2, ...objRest} = obj 
            	const formData = {
                	list: list?.map(item => {
                    	const {p1, ...itemRest} = item
                        return {
                        	...itemRest,
                            p2: p1
                        }
                    }),
                    obj: {
                    	 ...objRest,
                         date1: date1 && moment(date1).format("YYYY-MM-DD"),
                         num1: Number(num1),
                         num2: Number(num2),
                    }
                }
                setDetail(formData)
            } else {
            	throw Error(res.msg)
            }
        } catch (err) {
        	message.error(err?.message || '请求错误')
        }
    }
    
    

    这个应该是前端最基础的接口处理了,基本上囊括了我会碰到的各种问题。我感觉能用 ramdajs 或者 lodash/fp 等函数库把这个函数用函数式编程优化了,基本上就 fp 通关了

    4 条回复    2022-04-15 10:08:00 +08:00
    vance123
        1
    vance123  
       2022-04-14 22:35:49 +08:00 via Android
    问题应该不在过程式或是函数式。好的代码一次只做一件事,你这段代码一次做了 n 件事
    chenliangngng
        2
    chenliangngng  
    OP
       2022-04-14 22:45:52 +08:00
    @vance123 中间这个字段映射的部分呢
    ```javascript
    const {list, obj} = res.data;
    const {date1, num1 = 1, num2, ...objRest} = obj
    const formData = {
    list: list?.map(item => {
    const {p1, ...itemRest} = item
    return {
    ...itemRest,
    p2: p1
    }
    }),
    obj: {
    ...objRest,
    date1: date1 && moment(date1).format("YYYY-MM-DD"),
    num1: Number(num1),
    num2: Number(num2),
    }
    }
    ```
    GeruzoniAnsasu
        3
    GeruzoniAnsasu  
       2022-04-14 23:00:42 +08:00   ❤️ 4
    函数式的精髓在于「符号演算」,本质上是一些公式代换,所以是在处理复杂对象关系和约束时才比较好用,并不是说函数式就比过程式更优雅,先走出误区。

    再说实例。
    你展示的一个 getdetail 的过程:
    1. 调接口
    2. 验证拉取结果
    3. 对参数进行「变换」
    这个描述本身就非常过程化,有明确的分段步骤,并不存在关系约束的语义,所以用函数式写本来也不适合。

    当然也不是不可以,我们换个描述:

    1. setdetail 接受「 raw 数据的变换结果」,最终将结果闭包展开,暂时先不管它内部什么样
    2. 「 raw 变换结果」可以写为将「变换」应用到「 raw 」上 ← 函数化
    3. 「 raw 数据」可以看做将「请求提取子(包含验证子)」应用在「数据源」上←函数化
    4. 「数据源」是一个「输入请求类型然后重封装为响应类型的 monad 」←函数化
    5. 「请求类型」 由 「请求类型变换子」应用在「请求数据」上得到←函数化


    你觉得这优雅吗,我觉得一点也不,还非常麻烦和抽象,每一个「变换子」(即函数)都得绞尽脑汁才写出来,这些步骤也不可能比过程描述要少。


    像 map 和 filter 这样的函数已经是函数式最适用的最小场合了,提供一个输入数组和输出数组的约束函数,把这个约束应用在原数组上得到新数组。这不函数化吗,不够优雅吗?
    walpurgis
        4
    walpurgis  
       2022-04-15 10:08:00 +08:00   ❤️ 1
    去状态,首当其冲是减少 useState ,用 react query 或 swr 管理数据获取,getDetail 改成 return formData ,getDetail 就变成了一个伪纯函数,描述了 params 和 detail 的映射关系
    这么做从根本上避免了在快速改变 params 时,多个协程都去 setDetail 产生的竞态问题
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1323 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 17:44 · PVG 01:44 · LAX 09:44 · JFK 12:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.