In this series, I will read the source code of ahooks, which is used to familiarized myself with the writing method of custom hooks, and improve my ability to write custom hooks.

In order to distinguish it from the original comments of the code, the personal understanding section uses the beginning of ///, which is not related to the triple slash instruction, just to distinguish it.

Review past

  • Ahooks source code interpretation series
  • Ahooks Source Code Interpretation Series – 2
  • Ahooks Source Code Interpretation series – 3
  • Ahooks Source Code Interpretation series – 4

useDynamicList

Associating a unique key with a list item is appropriate for dynamic lists of ANTD forms, which can be problematic in other scenarios.

import { useCallback, useRef, useState } from 'react';

export default <T>(initialValue: T[]) = > {
  const counterRef = useRef(-1);/// Store the last key, increment
  // key memory
  /// corresponds to the contents of the list
  const keyList = useRef<number[] > ([]);// Internal method
  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 || [];
  });
  /// set the list to a newList, newList, instead of resetting the list to its original state
  const resetList = useCallback((newList: T[] = []) = > {
    keyList.current = []; /// The key memory is empty, but the key is not incremented from 0 again
    setList(() = > {
      (newList || []).forEach((_, index) = > {
        setKey(index);
      });
      returnnewList || []; }); } []);/// Insert a key at the same position in the keylist
  const insert = useCallback((index: number, obj: T) = > {
    setList((l) = > {
      const temp = [...l];
      temp.splice(index, 0, obj);
      setKey(index);
      returntemp; }); } []);/// returns the key of the specified index location data
  const getKey = useCallback((index: number) = > keyList.current[index], []);
  const getIndex = useCallback(
    (key: number) = > keyList.current.findIndex((ele) = > ele === key),
    [],
  ); /// Pass in the key and reverse lookup the corresponding data index value
  // set the key for the data to be merged, and then merge
  const merge = useCallback((index: number, obj: T[]) = > {
    setList((l) = > {
      const temp = [...l];
      obj.forEach((_, i) = > {
        setKey(index + i);
      });
      temp.splice(index, 0. obj);returntemp; }); } []);React key does not trigger rerender if the react key is used.
  const replace = useCallback((index: number, obj: T) = > {
    setList((l) = > {
      const temp = [...l];
      temp[index] = obj;
      returntemp; }); } []);const remove = useCallback((index: number) = > {
    setList((l) = > {
      const temp = [...l];
      temp.splice(index, 1);
      /// Try catch is used to prevent crashes when current does not exist
      // remove keys if necessary
      try {
        keyList.current.splice(index, 1);
      } catch (e) {
        console.error(e);
      }
      returntemp; }); } []);const move = useCallback((oldIndex: number, newIndex: number) = > {
    if (oldIndex === newIndex) {
      return;
    }
    setList((l) = > {
      const newList = [...l];
      // delete data from old index and move it to new index
      /// equivalent to newlist. splice(newIndex, 0... newList.splice(oldIndex, 1))
      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);
      }

      returntemp; }); } []);const push = useCallback((obj: T) = > {
    setList((l) = > {
      setKey(l.length);
      return l.concat([obj]); /// Concat is used because concat returns the merged array. Push returns the length of the new array. https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/concat}); } []);const pop = useCallback(() = > {
    // remove keys if necessary
    try {
      keyList.current = keyList.current.slice(0, keyList.current.length - 1);
    } catch (e) {
      console.error(e);
    }
    /// Again, slice is used because it returns the new array after the operation, while POP returns the deleted element
    setList((l) = > l.slice(0, l.length - 1)); } []);const unshift = useCallback((obj: T) = > {
    setList((l) = > {
      setKey(0);
      return[obj].concat(l); }); } []);/// This is not a method that can be used in all scenarios. This is for the demo where form.getFieldsValue() gets the form data and then sorts it.
  // The sortForm method is required to take effect. The following requirements must be met:
  // 1. The result source data passed in must always have the original index, so that their index is the same as the internal stored key
  If resetList is used, the new result index must start from the maximum value before the resetList is set, not from 0. Because the reset didn't start with the key reset to 0. For example, there are three data with index: 0,1,5. The result index of the new item after resetLis should be 6
  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,
  };
};

Copy the code

The resources

  • concat

The above content due to my level problem is inevitable error, welcome to discuss feedback.