Reprinted from Dazhao.com blog “Mailbox Recipient Component (React Version) Growing Up (II)”

I remember I wrote one beforeGrowth History of Mailbox Recipient Component (VUE Version) (I)I remember writing that I used editable divs for input, and also mentionedAt that time, out of the challenge of myself and bronze’s digging strength, I wanted to try a different solution, using editable div completely… This small digging strong for the follow-up many functional bottlenecks buried hidden dangers…

Disadvantages of using Contenteditable divs

What are the specific risks?

  1. Because clicking to insert a new recipient is actually inserting an empty recipient object into the array, frequent checks for extra empty objects are needed to ensure that users always have only one empty object when they randomly click. This results in frequent re-rendering of the array, making it difficult to click in to select elements.
  2. Ordinary users, products, and designers tend to think of the recipient component as an input box (have you ever seen an input box with a validation success icon), which causes their requirements and changes to be designed with input features that are not possible with contenteditable divs. For example, the user changes the background color of the entire component after focusing.

This time, when the project was migrated to React, we also made design adjustments to this part, using the mainstream input method to input and edit. The response click part is the same as before

The code structure

  1. There is only one input globally. To solve the problem of frequent null check, associate the input content with an index in the array. The index position is the insertion position of the input content, and the content after the index is naturally moved back one bit. Move the input to the corresponding index when you need to edit or insert content.
  2. Click on an area within the entire component but not outside of the existing recipient information (the blue box in the figure above) to add a new recipient at the end of the list, and move the input directly to the end of the list. Its input value is associated with the last of the current recipient array list with index list.length.
  3. Click on a recipient preview (the green box in the figure) to highlight it, if it is double-click to change it to edit (move input to the current recipient location, delete its data from the list, associate input with the recipient index, insert the index position after input is complete); If you click in front of it (the area indicated by the first small arrow), you move the input to the front of it, associate the input with the recipient index, and insert the new content into the index when the input is complete.
Code snippet:

React will re-render after changing the list data. According to the code structure above, the input will reappear at the end of the list. We need to move the input to the position it needs to appear through the ref in the diagram after rendering.

// Back to the car screen to insert data
  function onInputEnterInsert(data) {
    const result = getAutoCompleteResult(); // Whether search candidates are currently selected
    const finalData = result.value ? result : data; // If there is candidate information, directly insert the candidate information, ignoring the input information
    insertData(finalData);
    afterDataInserted(state.inputIndex);
  }
Copy the code

Insert data procedure

// Insert data into the list
  function insertData(data) {
    constdataInfo = { ... data,_addedTime: Date.now(), // convenience as key
    };
    if (isLastIndexOfList(state.inputIndex)) { // Add new ones
      list.push(dataInfo);
    } else { // Double-click to update
      list.splice(state.inputIndex, 0, dataInfo);
    }
    props.onChange(list.slice()); // Change state to trigger render
    clearAddress();
  }
Copy the code

Adjust the input position after rendering

Function afterDataInserted(indexBeforeInsert) {console.log('sis hook after INSERTED -> ', indexBeforeInsert, list[indexBeforeInsert], list); typeof afterEditHook === 'function' && afterEditHook(indexBeforeInsert, list[indexBeforeInsert], list); SetTimeout (() => {if (! IsLastIndexOfList (indexBeforeInsert)) {// As long as it is not inserted at the end, Needs to render the list after moved in the last input to the current last anchor nodes in the front of the const targetNode = containerRef. Current. The children [indexBeforeInsert + 1]; / / the list has to insert a new inside, so the original anchor node index + 1 containerRef. Current. The insertBefore (inputContainerRef. The current node, targetNode); // Dom adjustment fixes index and input pointing to dispatch({inputIndex: indexBeforeInsert + 1,}); } doInputFocus(0); }, 0); }Copy the code

It can be seen that some hooks have been added to facilitate the user to process other logic in the corresponding cycle. Previous Vue releases added some new features during product iterations

  1. Upper limit of list quantity
  1. This parameter is automatically selected if there is only one candidate list
  2. Recipient drag directly as well as drag across the bar

React also supports this function synchronously, which will be discussed in a separate article.