This article is reprinted from dazhao.com [Growth history of mailbox Recipient Component (3) Comparison of different data Schemes by dragging and dragging across the bar]. I wrote the recipient component a few days ago. It is actually a component that can be searched for skill input and displayed in the form of tags. Some problems were encountered in implementing the requirement that the mailbox addresses of multiple SIS components be able to be dragged and dropped from one another, similar to a clipping operation. For example, if you drag a mailbox address from SIS_A to sIS_B, the one in SIS_A will be removed.

Below is the code implementation, with comments on what each line does. The drag and drop array logic is simply written as a hook

// hooks.js import React from ‘react’; UseReducer export function useDispatch (initialState) {const [state, dispatch] = useReducer((state, action) => { return { … state, … action, } }, initialState);

const modifyStateWhileDispatch = (payload, value) => { if (toString.call(payload) ! == ‘[object Object]’) { payload = { [payload]: value, } } Object.assign(state, payload); // state changed(like vue) but dom not dispatch(payload); // dom changed with react }; return [state, modifyStateWhileDispatch]; }

/ * *

  • Uses the SIS component based on the specified count
  • @param count
  • @returns {[unknown[], setState]}

*/ export function useSis(count) { const [state, dispatch] = useDispatch(Array(count).fill(1).reduce((acc, curr, index) => ({ … acc, [index]: [] }), {})); // Initialize to {0: [], 1: [], 3: []}

function updateSis(index, value) { dispatch(index, value); }

return [Object.values(state), updateSis]; } code structure import {useDispatch, useSis} from ‘./ links.js ‘;

const Test = (props) => { const [state, dispatch] = useDispatch({ targetsArr: [], ccTargetsArr: [], bccTargetsArr: [],});

const { targetsArr, ccTargetsArr, bccTargetsArr } = state;

function updateSis(index, value) { const index2StringMap = [‘targetsArr’, ‘ccTargetsArr’, ‘bccTargetsArr’]; const target = index2StringMap[index]; dispatch({ … state, [target]: value, }) }

<! --> const [[targetsArr, ccTargetsArr, bccTargetsArr], updateSis] = useSis(3); <! Return ({<table> <tbody> <tr> <td>{window.i18n_data_mail['email.abstract. Recipient']}</ TD > < TD > <SmartInputSelect id="id4t_sis_targets" uniqueKey="sis0" onChange={(payload) => updateSis(0, payload)} fetchListMethod={fetchAddressList} validateMethod={validateEmail} list={targetsArr}/> </td> </tr> <tr style={{  display: emailConfig.showCc ? "' : 'none' }}> <td>{ window.i18n_data_mail['email.abstract.Cc'] }</td> <td> <SmartInputSelect id="id4t_sis_cc_targets" uniqueKey="sis1" onChange={(payload) => updateSis(1, payload)} fetchListMethod={fetchAddressList} validateMethod={validateEmail} list={ccTargetsArr}/> </td> </tr> <tr style={{ display: emailConfig.showBcc ? "' : 'none' }}> <td>{ window.i18n_data_mail['email.abstract.Bcc'] }</td> <td> <SmartInputSelect id="id4t_sis_bcc_targets" uniqueKey="sis2" limit={2} onChange={(payload) => updateSis(2, payload)} fetchListMethod={fetchAddressList} validateMethod={validateEmail} list={bccTargetsArr}/> </td> </tr> </tbody> </table> })Copy the code

}; export default Test; Function onDragStart(e) {e.datatransfer. setData(‘IM+MailAddress’, json.stringify ({index: Index, // Index of the element in the current SIS array data uniqueKey: uniqueKey, // the current SIS unique identifier data: {… data, } })); Function onDrop(e) {if (! allowDrop) { return; } const addressStr = e.dataTransfer.getData(‘IM+MailAddress’); if (! addressStr) { return; } e.preventDefault(); const addressInfo = JSON.parse(addressStr); const target = getDropTarget(e.target); Const targetIndex = target? target.tabIndex : list.length; Console. log(‘sis drag onDrop data -> ‘, addressStr); const newList = list.slice(); If (addressInfo.uniqueKey === uniqueKey) {// Move the element before the same SIS if (targetIndex === addressInfo.index) {// stay in place console.log(‘sis drag afterDrop1’); return; } else if(addressinfo.index > targetIndex) {// newlist.splice (addressInfo.index, 1); newList.splice(targetIndex, 0, { … addressInfo.data, }); props.onChange(newList); } else {// move newlist. splice(targetIndex, 0, {… addressInfo.data, }); newList.splice(addressInfo.index, 1); props.onChange(newList); }} else {// Move elements between sis newlist.splice (targetIndex, 0, {… addressInfo.data, }); props.onChange(newList); console.log(‘sis drag drop external -> ‘, list.length, JSON.stringify(list.slice()), uniqueKey, ‘ <== ‘, addressInfo.uniqueKey); / / notification source of external sis to remove MailMessageCenter. Drag and drop elements the publish (sism. Remove, [{key: addressInfo uniqueKey, index: addressInfo.index, }]); MailMessageCenter.publish(‘sism.removeOverIndicator’, [{ key: addressInfo.uniqueKey, }]); } removeOverIndicator(); console.log(‘sis drag afterDrop2’); } props. OnChange (newList); The specific parent component updates the data process in a timely manner.

The above processing process has been through the Vue version of the online long-term stable operation, I think there is no problem.

However, some problems were found during the React migration self-test, especially when the first hurdle drag was carried out, data loss was easy to occur.

In the first attempt, six elements were dragged and dragged between three sis. Finally, none of them were left and all of them were “eaten”. Second attempt: start with 6 elements being dragged between 3 sis, then “eat” one, then keep 5.

After switching to Plan B, you can see the SPECIFIC GIF and no problem has been found

In fact, there is no fundamental difference between plan A and Plan B in terms of code. Why should there be a difference? Is plan B simply not tested enough? But plan A has a high probability of bugs. For guidance…