如何在 React 组件的文本区域图标前添加

How to prepending before icon for text area for React component

我正在尝试实现 TextArea 的 React 版本,它会在我每次按下 Return/Enter 时附加“$”。

每次有人按回车键时,我都很难在前面加上一个符号 # 或 % 或美元。我该怎么做?

这是我的基本尝试,但我有点迷茫:

const MyComponent = () => {
  const [name, setName] = React.useState('');

  return (
    <div>
      <textarea value={name} onChange={(e) => { setName(e.target.value) }} />
    </div>
  );
}

ReactDOM.render(<MyComponent />, document.getElementById('root'));

希望我正确理解了您的意图,这是它的超级磨损版本。您可能需要稍微更改代码以适合您的用例。

import { useState, useEffect } from "react";

export default function App() {
  const [textValue, setTextValue] = useState("");
  const [displayedTextValue, setDisplayedTextValue] = useState("");

  useEffect(() => {
    let splitTextValue = textValue.split("\n");
    splitTextValue = splitTextValue.map((line, iter) => {
      if (iter === splitTextValue.length - 1) return line;
      if (line[0] !== "$") return "$ " + line;
      return line;
    });
    setDisplayedTextValue(splitTextValue.join("\n"));
  }, [textValue]);

  return (
    <div>
      <textarea
        value={displayedTextValue}
        onChange={(e) => {
          setTextValue(e.target.value);
        }}
      />
    </div>
  );
}

这是一个使用键事件的版本,我认为在处理依赖于键的事情时更清晰。

这是the repro on Stackblitz,这是代码:

import React from 'react';
import { render } from 'react-dom';

const App = () => {
  const enterKeyCode = 'Enter';
  const backspaceKeyCode = 'Backspace';

  const [val, setVal] = React.useState('$ ');
  const [keyCodeEvent, setKeyCodeEvent] = React.useState();

  React.useEffect(() => {
    if (keyCodeEvent) {
      // Handle numpad 'enter' key
      if (keyCodeEvent[0].includes(enterKeyCode)) {
        setVal(`${val}\n$ `);
      } else if (keyCodeEvent[0] === backspaceKeyCode) {
        setVal(`${val.slice(0, -1)}`);
      } else {
        setVal(`${val}${keyCodeEvent[1]}`);
      }
    }
  }, [keyCodeEvent]);

  return (
    <div>
      {/* Empty onChange to prevent warning in console */}
      <textarea onKeyDown={e => setKeyCodeEvent([e.code, e.key])} value={val} onChange={() => {}} />
    </div>
  );
};

render(<App />, document.getElementById('root'));

我阅读了您对 Marko Borković 的回答的评论,所以我处理了退格键,但是 他说的完全正确 您应该为此构建一个特殊组件。这将更容易改进和清洁。如果您想向您的组件添加功能,您将无法避免其他一些错误。

好的,所以我手上有一点时间,我认为这可能是一次很好的学习经历。所以我向你介绍:MoneyInputList

import './css/MoneyInputList.css'

import { useState, useEffect } from 'react';

let latestAdded = 'moneyInputList-input-0';
let lastSize = 0;

const MoneyInputList = () => {
    const [recordList, setRecordList] = useState({data: ['']});


    const handleFormSubmit = (e) => {
        e.preventDefault();
        if(recordList.data[recordList.data.length-1] !== ''){
            setRecordList({data: [...recordList.data, '']})
        }
    };

    useEffect(() => {
        if(lastSize !== recordList.data.length)
            document.getElementById(latestAdded).focus();

        lastSize =  recordList.data.length;
    }, [recordList]);

    
    return (
        <form autoComplete='off' onSubmit={handleFormSubmit}>
            <div className="main-container">
                {recordList.data.length > 0 &&
                    recordList.data.map((record, iter) => {
                        latestAdded = "moneyInputList-input-"+iter;
                        return (
                        <div key={"moneyInputList-field-"+iter} className="record-field">
                            <div className="record-sign">$</div>
                            <input className="record-input" id={"moneyInputList-input-"+iter} value={recordList.data[iter]} onChange={(e) => {

                                if(e.target.value === '' && iter !== recordList.data.length-1){
                                    let modifiedData = [];
                                    recordList.data.forEach((e,i) => {
                                        if(i !== iter)
                                            modifiedData.push(e);
                                    });
                                    setRecordList({data: modifiedData});
                                    return;
                                }

                                const filteredValue = e.target.value.split('').filter(e=>(e.charCodeAt() >= '0'.charCodeAt() && e.charCodeAt() <= '9'.charCodeAt()));
                                

                                let formattedValue = [];
                                filteredValue.forEach((elem, i) => {
                                    if((filteredValue.length - i) % 3 === 0 && i !== 0)
                                        formattedValue.push(',');
                                    formattedValue.push(elem);
                                });
                                formattedValue = formattedValue.join('');
                                e.target.value = formattedValue;

                                let myData = recordList.data;
                                myData[iter] = e.target.value;
                                setRecordList({data: myData});
                            }} type="text"/>
                        </div>
                    )})
                }
            </div>
            <input style={{flex: 0, visibility: 'collapse', height: 0, width: 0, padding: 0, margin: 0}} type="submit"/>
        </form>
    )
}

export default MoneyInputList;


这个组件应该做你需要它做的事情。这不是最好的代码,但它可以工作。您可以看到它正在运行 here。当然,您可能仍然需要更改一些东西以使其适合您的代码库并可能实现 redux,但总体思路就在这里。您可以通过键入任何您想要的数字来使用它,按回车键将创建一个新行,删除一行的内容将删除它。