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)