小程序 / rax / ahooks / 可增删改的动态列表hooks

最近接触的都是小程序的项目,所以增长了不少关于小程序的知识点,目前觉得最有用的就是此篇文章所记录的 — 可增删改查列表。所用原理比较简单,就是声明list变量,在需要的地方遍历list渲染所需的内容,通过内部的 push / remove 等方法去改变所渲染内容。下面是所用代码与示例

hoosk.ts

此文件声明、导出所需方法

import { useCallback, useRef, useState } from 'rax';
/**
 * 可增删改的动态列表hooks
 */
export default <T>(initialValue: T[]) => {
  const counterRef = useRef(-1);
  // key 存储器
  const keyList = useRef<number[]>([]);

  // 内部方法
  const setKey = useCallback((index: number) => {
    counterRef.current += 1;
    keyList.current.splice(index, 0, counterRef.current);
  }, []);

  const [list, setList] = useState(() => {
    (initialValue || []).forEach((_, index) => {
      setKey(index);
    });
    return initialValue || [];
  });

  const resetList = useCallback((newList: T[] = []) => {
    keyList.current = [];
    setList(() => {
      (newList || []).forEach((_, index) => {
        setKey(index);
      });
      return newList || [];
    });
  }, []);

  const insert = useCallback((index: number, obj: T) => {
    setList((l) => {
      const temp = [...l];
      temp.splice(index, 0, obj);
      setKey(index);
      return temp;
    });
  }, []);

  const getKey = useCallback((index: number) => keyList.current[index], []);
  const getIndex = useCallback(
    (key: number) => keyList.current.findIndex((ele) => ele === key),
    [],
  );

  const merge = useCallback((index: number, obj: T[]) => {
    setList((l) => {
      const temp = [...l];
      obj.forEach((_, i) => {
        setKey(index + i);
      });
      temp.splice(index, 0, ...obj);
      return temp;
    });
  }, []);

  const replace = useCallback((index: number, obj: T) => {
    setList((l) => {
      const temp = [...l];
      temp[index] = obj;
      return temp;
    });
  }, []);

  const remove = useCallback((index: number) => {
    setList((l) => {
      const temp = [...l];
      temp.splice(index, 1);

      // remove keys if necessary
      try {
        keyList.current.splice(index, 1);
      } catch (e) {
        console.error(e);
      }
      return temp;
    });
  }, []);

  const move = useCallback((oldIndex: number, newIndex: number) => {
    if (oldIndex === newIndex) {
      return;
    }
    setList((l) => {
      const newList = [...l];
      const temp = newList.filter((_: {}, index: number) => index !== oldIndex);
      temp.splice(newIndex, 0, newList[oldIndex]);

      // move keys if necessary
      try {
        const keyTemp = keyList.current.filter((_: {}, index: number) => index !== oldIndex);
        keyTemp.splice(newIndex, 0, keyList.current[oldIndex]);
        keyList.current = keyTemp;
      } catch (e) {
        console.error(e);
      }

      return temp;
    });
  }, []);

  const push = useCallback((obj: T) => {
    setList((l) => {
      setKey(l.length);
      return l.concat([obj]);
    });
  }, []);

  const pop = useCallback(() => {
    // remove keys if necessary
    try {
      keyList.current = keyList.current.slice(0, keyList.current.length - 1);
    } catch (e) {
      console.error(e);
    }

    setList((l) => l.slice(0, l.length - 1));
  }, []);

  const unshift = useCallback((obj: T) => {
    setList((l) => {
      setKey(0);
      return [obj].concat(l);
    });
  }, []);

  const sortForm = useCallback(
    (result: unknown[]) =>
      result
        .map((item, index) => ({ key: index, item })) // add index into obj
        .sort((a, b) => getIndex(a.key) - getIndex(b.key)) // sort based on the index of table
        .filter((item) => !!item.item) // remove undefined(s)
        .map((item) => item.item), // retrive the data
    [],
  );

  const shift = useCallback(() => {
    // remove keys if necessary
    try {
      keyList.current = keyList.current.slice(1, keyList.current.length);
    } catch (e) {
      console.error(e);
    }
    setList((l) => l.slice(1, l.length));
  }, []);

  return {
    list,
    insert,
    merge,
    replace,
    remove,
    getKey,
    getIndex,
    move,
    push,
    pop,
    unshift,
    shift,
    sortForm,
    resetList
     };
};

index.jsx

此文件用来运用、示例方法

import { createElement, useEffect } from 'rax';
import hooks from './hooks';

function Index() {
// 此处的hooks被调用时括号内为空,实际上可以在括号内传入参数,即可成为list的初始值,不传参则list为[]空数组
const { list, push, remove, replace } = hooks();

  useEffect(() => {
  // 需要在组件第一次加载的时候,根据自己的需要去渲染相应个数的初始态组件,以form为力,首先渲染一个form.item
   if (list.length < 1) {
      push({name:1});
    }
  }, [ list, push, remove, replace ]);
  
   function onSubmit(val, error) {
    if (error) return;
    // 这里是push进入了一个空对象,实际上可以在对象中添加属性,而添加进的属性,可以在list被遍历时添加到each当中,例如上面的 push({name:1});
      push({});
  }
  
return (
    <Form
      idx={list.length}
      onSubmit={onSubmit}
    >
          {
            list.map((each, idx) => (
            <>
             <Form.Item  label={`用户名${idx}`} required requiredMessage="Must Input User Name">
	            <Input name={`username${each?.name}`} placeholder="Please Input User Name" />
	          </Form.Item>
	          {/* 
	          此处的替换传入的也是空值,实际上功能等同于清空当前值,若传入值则可以在当前idx下给each传入属性,比如input的默认值等,更多功能可自行想象与实践
	           */}
	           <Button key={`replace${idx}`} model="solid" type="normal" onClick={()=> replace(idx, {})}>
	         	替换
	          </Button>
	          {/* 
	          删除比较好理解,传入当前索引即可
	           */}
	          <Button key={`remove${idx}`} model="solid" type="normal" onClick={()=> remove(idx)}>
	         	删除
	          </Button>
	          </>
            ))
          }
         
          <Form.Submit type="secondary" model="text" size="small">
         	添加
          </Form.Submit>
    </Form>
  );
}

具体实现效果因项目保密原因无法展示,类似效果如图
具体实现效果因项目保密原因无法展示,类似效果如图

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值