【react+ts- forwardRef】

文章介绍了在React中使用TypeScript(TS)和AntDesign(Antd)时,如何通过forwardRef进行组件间的引用传递,特别是对于input组件和Form组件的焦点控制及状态访问。通过示例代码展示了JS和TS两种版本的实现方式,以及在AntdForm中如何进行ref的透传。


引用传递(Ref forwading)是一种通过组件向子组件自动传递 引用ref 的技术。对于应用者的大多数组件来说没什么作用。但是对于有些重复使用的组件,可能有用。例如某些input组件,需要控制其focus,本来是可以使用ref来控制,但是因为该input已被包裹在组件中,这时就需要使用Ref forward来透过组件获得该input的引用。

作者:pipu
链接:https://www.jianshu.com/p/fac884647720/
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

1. 学习资料

JS-react forward ref高阶组件透传-1
JS-react forward ref高阶组件透传-2
TS-react forward ref高阶组件透传

2. 普通input透传

2.1 TS版本

Parent.tsx

import React, { useRef, useState } from 'react'
import Child from './Child';

export default function Parent() {
  const inputRef = useRef<HTMLInputElement>(null);
  const [text,setText] = useState<string>('');
  return (
    <div>
      <button onClick={()=>{
        inputRef.current?.focus();
        setText('');
      }}>父组件内按钮-点击input获取焦点并清空value</button>
      <Child ref={inputRef} text={text} changeVal={(val:string)=>{
        setText(val);
      }}></Child>
    </div>
  )
}

Child.tsx

import React, { ChangeEvent, forwardRef, MutableRefObject, useCallback, useRef } from 'react'

interface Iprops {
  text:string;
  changeVal:Function
}

const Child = forwardRef<HTMLInputElement,Iprops>((props,ref) => {
const localRef = useRef<HTMLInputElement | null>(null);

const onChange = useCallback((e:ChangeEvent<HTMLInputElement>)=>{
  props.changeVal(e.target.value)
},[props]);

return (
  <div>
    <input type="text" value={props.text} ref={el=>{
      localRef.current = el;
      console.log(ref)
      if (typeof ref === 'function') {
        ref(el);
      } else if (ref) {
        (ref as MutableRefObject<HTMLInputElement>).current = el!;
      }
    }} onChange={onChange}/>
    <button onClick={()=>{
      console.log(localRef.current)
      console.log(localRef.current?.value)
      console.log(props.text)
    }}>子组件内按钮-点击获取input输入值</button>
  </div>
)
}) 

export default Child

2.2 JS版本

Child.tsx

import React, { forwardRef, useCallback} from 'react'
const Child = forwardRef((props,ref) => {
	const onChange = useCallback((e)=>{
	  props.changeVal(e.target.value)
	},[props]);

	return (
	  <div>
	    <input type="text" value={props.text} ref={ref} onChange={onChange}/>
	    <button onClick={()=>{
	      console.log(ref.current)
	      console.log(ref.current.value)
	      console.log(props.text)
	    }}>子组件内按钮-点击获取input输入值</button>
	  </div>
	)
}) 

export default Child

3. TS-Antd-Form组价透传

Parent.tsx

import React, { useRef } from 'react'
import type { FormInstance } from 'antd/es/form';
import Child from './Child';

export default function Parent() {
  const addForm = useRef<FormInstance>(null);
  const updateForm= useRef<FormInstance>(null);
  return (
    <div>
      <button onClick={()=>{
        addForm.current?.validateFields()
        	.then((values) => {
        		console.log(values);
        	})
        	.catch((err) => {
		        console.log(err);
		     });
        
      }}>父组件内按钮-点击input获取焦点并清空value</button>
      <UserForm ref={addForm} regionList={regionList} roleList={roleList} />
      <UserForm ref={updateForm} regionList={regionList} roleList={roleList} />
    </div>
  )
}

Child.tsx

import React, { forwardRef, MutableRefObject, Ref, useEffect} from "react";
import { Form } from "antd";
import type { FormInstance } from 'antd/es/form';

interface UserFormProps {
  isUpdateRegionDisabled?:boolean;
  regionList:any[];
  roleList:any[];
}
const assignRefs = <T extends unknown>(...refs: Ref<T | null>[]) => {
  return (node: T | null) => {
    refs.forEach((r) => {
      if (typeof r === "function") {
        r(node);
      } else if (r) {
        (r as MutableRefObject<T | null>).current = node;
      }
    });
  };
};

const UserForm = forwardRef<FormInstance,UserFormProps>((props,ref)=>{
	const localRef = React.useRef<FormInstance | null>(null);
	useEffect(() => {
    	console.log('localRef',localRef.current)
  	}, [props]);
	return (
		<Form layout="vertical" ref={assignRefs(localRef, ref)}></Form>
	)
})
React和TypeScript中实现拖放图片功能,你可以使用`react-dnd`库,它是一个强大的JavaScript库用于处理用户界面元素的拖放操作。以下是简单的步骤: 1. **安装依赖**: 首先,你需要通过npm或yarn安装`react-dnd`和它的相关库: ```bash npm install react-dnd react-dnd-html5-backend ``` 2. **导入并配置**: 导入必要的模块,并在项目中创建一个DragDropContext: ```typescript import { DragDropContext, Droppable, Draggable } from 'react-dnd'; import HTML5Backend from 'react-dnd-html5-backend'; const MyComponent = React.forwardRef<HTMLDivElement>((props, ref) => { //... }); const dragDropConfig = { backend: HTML5Backend, }; ``` 3. **创建Draggable组件**: 对于可拖动的图片,创建一个Draggable组件,提供图片作为数据: ```typescript const DraggableImage = (dragImage: any) => ( <Draggable key={dragImage.id} type="image"> {(provided, snapshot) => ( <img src={dragImage.src} {...provided.dragHandle()} onDragStart={(event) => event.dataTransfer.setData('text/plain', dragImage.id)} /> {provided.placeholder} )} </Draggable> ); ``` 4. **设置Droppable区域**: 创建一个可以放置图片的目标区域,当有图片被拖放到这里时会触发相应的事件: ```typescript const DropZone = () => ( <Droppable droppableId="drop-area" onDrop={(acceptedItems) => handleDrop(acceptedItems)}> {provided => ( <div ref={ref} {...provided.droppableProps}> <h3>Drop an image here</h3> {provided.placeholder} </div> )} </Droppable> ); function handleDrop(acceptedItems) { acceptedItems.forEach((item) => console.log('Dropped:', item.type, item.id)); } ``` 5. **完整的组件示例**: ```typescript export default DragDropContext(dragDropConfig)(function App() { // 省略图片数组和dragImage的定义 return ( <div className="App"> <DropZone /> {/* 图片数组循环渲染 DraggableImage */} </div> ); }); ``` 记得将`dragImage`替换为你实际的数据结构,比如从服务器获取的图片列表。这就是基本的React + TypeScript拖放图片的实现。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值