react创建自定义组件_为您的React Web应用程序创建一个自定义自动调整大小的textarea组件...

react创建自定义组件

One of the weakest points of the web are the native form controls provided by web browsers. Although some great efforts are being done by browser vendors to improve what we get from plain old HTML, many useful elements are still missing.

Web的最弱点之一是Web浏览器提供的本机表单控件。 尽管浏览器供应商正在做一些巨大的努力来改进我们从普通的旧HTML中获得的内容,但是仍然缺少许多有用的元素。

One example of a pretty darn useful form input that is missing is a text area that grows in size along with its content. Most of the times when you have a text area in your web application, you don't actually know how much text your users are going to enter, and having your users deal with scrollbars when editing text provides them with a bad UX, especially on touchscreen devices.

一个缺少有用的非常有用的表单输入的示例是一个文本区域,该文本区域的大小和内容一起增加。 在大多数情况下,Web应用程序中都有文本区域时,您实际上并不知道用户将要输入多少文本,并且在编辑文本时让用户处理滚动条会给用户带来不良的用户体验,尤其是在触摸屏设备。

The best solution to this problem is a textarea that adapts its size to its content, and in this article we are gonna be building exactly that. There are many packages available on npm that already solve this problem, such as react-textarea-autosize, but building your own stuff is always exciting, right? Outside of being able to customize the functionality of your component however you like, you will also be learning about how hooks and refs works in React. Sounds fun, doesn't it? 🙂

解决此问题的最佳方法是根据其内容大小调整文本区域,在本文中,我们将对此进行精确构建。 npm上有许多可以解决此问题的软件包,例如react-textarea-autosize ,但是构建自己的东西总是令人兴奋的,对吗? 除了能够根据需要自定义组件的功能之外,您还将学习钩子和引用在React中的工作方式。 听起来很有趣,不是吗? 🙂

1.创建基础组件 (1. Creating the base component)

We want to start with a simple component that returns a <textarea />. In order to use hooks, we are going to create a functional component. Whether you use the classical function syntax or the arrow functional one is up to you:

我们想从返回<textarea />的简单组件开始。 为了使用钩子,我们将创建一个功能组件。 是否使用经典函数语法还是使用箭头函数语法取决于您:

import React, { useState, CSSProperties, useEffect, useRef } from "react";


const AutoTextArea = () => {
	const textAreaRef = useRef<HTMLTextAreaElement>(null);
	const [text, setText] = useState("");
	const [textAreaHeight, setTextAreaHeight] = useState("auto");
	const [parentHeight, setParentHeight] = useState("auto");


	const parentStyle: CSSProperties = {
		minHeight: parentHeight,
	};


	const textAreaStyle: CSSProperties = {
		height: textAreaHeight,
	};


	return (
		<div style={parentStyle}>
			<textarea
				ref={textAreaRef}
				style={textAreaStyle}
				rows={1}
			/>
		</div>
	);
};


export default AutoTextArea;

Let's go over a few details of this implementation:

让我们来看一下该实现的一些细节:

  1. On the first line of the component we are creating a ref for the textarea element. This allows us to access its DOM node whenever we want and retrieve its properties. In our case, the scrollHeight property will be extremely useful;

    在组件的第一行,我们为textarea元素创建一个引用。 这使我们可以随时访问其DOM节点并检索其属性。 在我们的例子中,scrollHeight属性将非常有用。
  2. On the following lines we declare three state variables. Their names are pretty self explanatory;

    在以下几行中,我们声明三个状态变量。 他们的名字很容易说明。
  3. Next up we have the return statement with our JSX code. The reason we have a div enclosing the textarea is to prevent some scrolling problems that occur when we don't have it. We are also setting custom styles for the elements using the state variables.

    接下来,我们有带有我们的JSX代码的return语句。 我们将div封闭在textarea中的原因是为了防止在我们没有文本区域时出现一些滚动问题。 我们还使用状态变量为元素设置自定义样式。

2.创建onChange处理程序和useEffect回调 (2. Creating the onChange handler and useEffect callback)

Now that we have our basic component that returns a textarea, we need to add the auto resize functionality:

现在我们有了返回文本区域的基本组件,我们需要添加自动调整大小功能:

useEffect(() => {
		setParentHeight(`${textAreaRef.current!.scrollHeight}px`);
		setTextAreaHeight(`${textAreaRef.current!.scrollHeight}px`);
	}, [text]);


	const onChangeHandler = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
		setTextAreaHeight("auto");
		setParentHeight(`${textAreaRef.current!.scrollHeight}px`);
		setText(event.target.value);
	};

When the textarea triggers an onChange event (i.e. when the user types something in it), our onChangeHandler sets the textarea's height to "auto", the parent div's height to the textArea's scrollHeight and updates the text state variable with the textarea's value. The reason we are resetting the textarea's height to auto is to ensure that it doesn't build up indefinitely in case the textarea has a padding greater than 0. Try commenting out that line, and see what happens when you enter any text:

textarea触发一个onChange事件时(即,当用户在其中键入内容时),我们的onChangeHandler将textarea的高度设置为“ auto”,将父div的高度设置为textArea的scrollHeight,并使用textarea的值更新文本状态变量。 我们将textarea的高度重置为auto的原因是为了确保在textarea的填充大于0的情况下不会无限期地建立它。尝试注释掉该行,并查看输入任何文本时会发生什么:

Image for post
We don't want that!
我们不想要那个!

Another odd thing we do is set the text variable with the textarea's content. We are doing this merely to keep track of when we should update the state variables that dictate the component's height, and this translates to adding a reference to the text variable on our useEffect's dependency array.

我们所做的另一件奇怪的事情是使用textarea的内容设置text变量。 我们这样做只是为了跟踪何时应该更新指示组件高度的状态变量,这意味着在useEffect的依赖项数组上添加了对文本变量的引用。

Finally, inside the useEffect hook, we set our textarea's height to its own scrollHeight. This happens after the onChangeHandler and before the next rerender, and even though technically the textarea is rendered with its size set to "auto" for a fraction of a second, your users won't notice it. What we can do however, is set some breakpoints on our code to see the action happening one step at a time.

最后,在useEffect挂钩中,我们将textarea的高度设置为其自己的scrollHeight。 这种情况发生在onChangeHandler之后和下一次重新渲染之前,即使从技术上讲,将textarea的大小设置为“ auto”一秒钟的时间后才进行渲染,但用户不会注意到它。 但是,我们可以做的是在代码上设置一些断点,以查看该操作一次只发生一步。

Image for post

3.最后的修饰 (3. Final touches)

The final code we have should look something like this:

我们拥有的最终代码应如下所示:

import React, {
	useState,
	useEffect,
	useRef,
	TextareaHTMLAttributes,
} from "react";


const AutoTextArea = (props: TextareaHTMLAttributes<HTMLTextAreaElement>) => {
	const textAreaRef = useRef<HTMLTextAreaElement>(null);
	const [text, setText] = useState("");
	const [textAreaHeight, setTextAreaHeight] = useState("auto");
	const [parentHeight, setParentHeight] = useState("auto");


	useEffect(() => {
		setParentHeight(`${textAreaRef.current!.scrollHeight}px`);
		setTextAreaHeight(`${textAreaRef.current!.scrollHeight}px`);
	}, [text]);


	const onChangeHandler = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
		setTextAreaHeight("auto");
		setParentHeight(`${textAreaRef.current!.scrollHeight}px`);
		setText(event.target.value);


		if (props.onChange) {
			props.onChange(event);
		}
	};


	return (
		<div
			style={{
				minHeight: parentHeight,
			}}
		>
			<textarea
				{...props}
				ref={textAreaRef}
				rows={1}
				style={{
					height: textAreaHeight,
				}}
				onChange={onChangeHandler}
			/>
		</div>
	);
};


export default AutoTextArea;

Some adjustments I have made to make the component even better are:

为了使组件更好,我进行了一些调整:

  1. Adding a props argument to the component, which is then passed to the textarea element, this ensures that our component can be used just like a plain old HTML textarea thoughout our website.

    向该组件添加一个props参数,然后将其传递给textarea元素,这可确保在我们的网站上可以像普通的旧HTML textarea一样使用我们的组件。
  2. Calling the onChange callback that is provided on the props object inside our onChangeHandler. This allows the onChange event handler to function normally from outside our custom component.

    调用onChangeHandler内部props对象上提供的onChange回调。 这使onChange事件处理程序可以从我们的自定义组件外部正常运行。

And voilà, let's look at the final result:

瞧,我们来看一下最终结果:

Image for post
Looks pretty neat, imo 😅
看起来很整洁,imo😅

翻译自: https://medium.com/@lucasalgus/creating-a-custom-auto-resize-textarea-component-for-your-react-web-application-6959c0ad68bc

react创建自定义组件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值