Drag Data Loading by ReactHooks+ReactDnd

Posted by jrtaylor on Tue, 15 Oct 2019 09:16:11 +0200

Drag to load API fields

Implement automatic loading of API by dragging a background API to Form with the mouse, so the fields become forms.
Drag component uses react-dnd plug-in, data interaction and page updating are implemented by Hooks.
Hooks Official Documents https://react.docschina.org/docs/hooks-intro.html
ReactDnd official document http://react-dnd.github.io/react-dnd/

Implementation process

data source

http://jianjiacheng.com/json/swagger.json

Project structure

Implementation process

Design sketch

Demo source code

https://github.com/jianjiachenghub/ReactHooksDnD.git

Drag Load Component Encapsulation DragBox

Components need to use useDrag, a dnd plug-in encapsulated hook
Then assign the function returned by hook to the ref attribute of DOM for operation.
Items are the representation of drag data and are represented by Object.

import React from 'react'
import { useDrag } from 'react-dnd'
import { Menu, Icon ,Button} from 'antd';
const DragBox = ({ name, data }) => {
    const [{ opacity }, drager] = useDrag({
        item: { name, type:'dragBox',data},
        collect: monitor => ({
            opacity: monitor.isDragging() ? 0.4 : 1,
        }),
    })
    return (
       <div ref={ drager }><Button value="large" type="dashed" block>{name}</Button></div>
    )
}
export default DragBox

Dustbin, a component that accepts drags

The accept attribute specifies that the type in the item that can only accept drag is dragBox
drop is a callback that listens for sliding completion

import React from 'react'
import { useDrop } from 'react-dnd'
import CreactForm from "./CreactForm"
const style = {
    minHeight: 780,
    height: '100%',
    border: '1px dashed black'
}
const Dustbin = ({onDrop,data}) => {
    const [{ isOver, canDrop }, drop] = useDrop({
        accept: 'dragBox',
        drop: onDrop,
        collect: monitor => ({
            isOver: monitor.isOver(),
            canDrop: monitor.canDrop(),
        }),
    })


    const getForm = (data)=>{
        if (Object.keys(data).length !== 0) {
            const {data:{properties}} = data
            return <CreactForm data={properties}/>
        }
    }
    return (
        <div ref={drop} style={{ ...style}}>
            {getForm(data)}
        </div>
    )
}
export default Dustbin

Display Component DndMenu of Interface

The JS code part of this data parses the data and passes it to the subcomponents

       <Layout>
           <Sider>
               {returnData.map(({ name, data }, index) => (
                   <DragBox
                       name={name}
                       data={data}
                       key={index}
                   />
               ))}
           </Sider>
           <Content>
               <Dustbin
                   onDrop={item => handleDrop(item)}
                   data={dropData}
               />
           </Content>
       </Layout>

Enabling DND needs to be placed in DndProvider


import React from 'react'
import ReactDOM from 'react-dom'
import DndMenu from './menu'
import { DndProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'

function Dnd() {
    return (
        <div className="App">
            <DndProvider backend={HTML5Backend}>
                <DndMenu />
            </DndProvider>
        </div>
    )
}
export default Dnd

Noticeable Problems of HOOKS Components

useEffect() request data logic

  • useEffect() lets you perform side effects in function components
  • By default, it executes after the first rendering and after each update.
  • But we don't need to have side effects again when updating.
  • The second parameter tells react to execute the side-effect function we passed on only when the value of this parameter changes.
  • You can perform side effects with an empty array in the second parameter of effect to indicate that no changes in values are monitored.
    useEffect(() => {
        getData()
    },[]);
  • Here we use await to parse the data returned by axios and call the update function.


    const getData = async () => {
        const result = await axios(
            `${GLOBAL_URL}/list`
        );
        console.log(result)
        const data = result.data[0]
        const api = getKey(data.apiPath)
        getTreeData(api,data.apiPath)
        const originalData = getOriginalData(data.apiPath,data.apiDefinitions)
        setData(originalData)
    }
    
    const [returnData, setData] = useState([]);//Rendering UI based on returnData

Data Exchange between Functional Components

Previously, using this.props inside the child component when using Class grammar can get the data passed by the parent component.
Now the functional grammar can use deconstruction assignment to get the data passed by the upper layer directly in the parameters of the sub-components.

const DragBox = ({ name, data }) => {
}


function DndMenu(props) {
    return (
        <DragBox
           name={name}
           data={data}
           key={index}
        />
    )
}

How hooks components use AntDesign form functions

Previous Class grammar requires only class modifier @ after calling functions of Form in Ant within a component.
You can use this.props to invoke the API to form inside the component

@Form.create()
@connect(({ usersModal, basicdata, loading }) => ({
  usersModal,
  basicdata,
  loading : loading.models.usersModal,
  loadingEditFlag : loading.effects['usersModal/saveEditFlag'],
  loadingUpdate : loading.effects['usersModal/UpdateUser'],
  loadingGet : loading.effects['usersModal/getUser'],
  loadingAdd : loading.effects['usersModal/addUser'],
}))
class UserDetail extends PureComponent {
}

Now you can export the component directly into the function returned by Form.create().

export default Form.create()(DndMenu)

Topics: Javascript React github JSON Attribute