很抱歉,经过长时间的解释,问题就在最后。
在reactjs网站(https://reactjs.org/docs/forms.html)上有一个示例,如下所示:
handleChange(event) {
this.setState({value: event.target.value.toUpperCase()});
}
这些教程通常表示在按下某个键时以受控形式(例如在输入字段中),然后调用onChange,调用调用setState的handleChange事件,并重新呈现该组件,该组件将显示改变了的价值。但这不是全部真相。当本机DOM输入字段调用onChange时,输入字段已经'#34;呈现"通过浏览器,React不会重新渲染它。实际上,它将(重新渲染的)虚拟DOM元素的状态与本机DOM元素的状态进行比较,然后它发现没有差异,因此它什么都不做。在这种情况下,操作没有副作用(除了更改组件的状态)。
我知道对于初学者来说,在本教程的开头,一次讲述整个故事可能会让人感到困惑。但是这个" toUpperCase()"本教程中的示例具有误导性,因为它表明通过在handleChange中将值更改为value.toUpperCase()将使组件仅接受带有字母的字母,没有副作用。但事实并非如此,任何人都可以尝试这样做:只需在输入字段的中间选择一部分文本,然后按一个键。它肯定会转换为大写,但在这种情况下,React将重新设置输入的value属性,使文本光标(插入点)移动到文本的末尾。这是一个副作用,可能非常分散。例如,如果用户想要替换文本中间的单词,那么他就无法以任何实际的方式进行替换。他会说这是错的,它不起作用 - 他会说得对。在这种特殊情况下,我知道我可以设置text-transform:大写并将小写版本存储在商店中,但这也是错误的:如果我需要它是大写的,那么它当然应该是大写的在商店。视图的行为不得确定存储中的数据表示形式。视图应该只是视图,而不是其他任何内容。
我检查了许多与React相关的教程,并且所有这些教程都有#34;缺陷"。例如,这是来自reactjs.org的图表,显示了Flux的作用:
它表示在操作通过调度程序,存储区,然后是控制器视图后,视图将呈现。但实际情况是,View不仅会发出动作。它还会在发出动作之前改变其外观。 React希望将DOM元素视为发出动作的视图,但实际上它们会做其他事情。
使用select元素在reactjs教程中出现了同样的错误。 (https://reactjs.org/docs/forms.html)他们只是通过更改" multiple = {true}"属性,你可以有一个多选。不,你不能,它只是不起作用。当您在多选中选择多个项目时,浏览器将多次调用onChange事件:对所选的每个项目单独调用。因此,将组件的状态设置为所选项的集合(至少不是来自事件处理程序)是不可能的。我可以设置一个计时器,收集从onChange发出的所有更改,最后用收集的项调用setState()。但这违反了React的规则,因为应该有一个单一的事实来源。在这种情况下,将有多个来源(至少有一段时间,直到收集所有事件)。任何人都可以看到在具有许多异步处理程序的复杂应用程序中,这最终会导致难以调试的错误。
一个非常简单的事情("只接受输入框中的大写字母")对我来说似乎很难正确完成。要么我必须在JavaScript中实现我自己的输入框,要么为输入字段编写自定义渲染方法,以便在值更改时将光标位置保持在正确的位置。两者似乎都是坏主意。
在谷歌搜索后,我注意到有大量组件重新实现原生元素。为React编写了数百个select和multiselect组件,我怀疑这部分是因为本机DOM元素的行为方式。 (例如,他们不是纯粹的观点。)
问题:有没有人使用本机DOM组件做出反应?如果是这样,你如何实现真正的"控制"没有副作用的行为?可能吗?或者我应该不关心,并选择专门为React编写的某种UI工具包? (但即使有了这些,实现"大写输入字段"可能需要额外的编程。)
答案 0 :(得分:3)
这应该足够了:
handleChange(event) {
const input = event.target;
const start = input.selectionStart;
const end = input.selectionEnd;
this.setState(
{value: input.value.toUpperCase()},
() => input.setSelectionRange(start, end)
);
}
同时检查:http://blog.vishalon.net/javascript-getting-and-setting-caret-position-in-textarea
答案 1 :(得分:1)
你说的是对的,但问题不是来自React,它来自浏览器本身。
考虑以下示例:
function handler() {
const elt = document.getElementById('test');
elt.value = elt.value.toUpperCase();
};

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<input id="test" type="text" value="default value" onKeyPress="handler();" />
</body>
</html>
&#13;
在谈论React之前,你怎么能让它工作? React无法覆盖浏览器行为。
如果你想在保持光标位置的同时大写所有内容,你可以查看使用草稿js的富文本编辑。
答案 2 :(得分:1)
简单:提交后使用CSS +规范化(toUpperCase()
)
text-transform: uppercase;
答案 3 :(得分:1)
我编写了简单的toInputUppercase
函数,该函数重写e.target.value
并将属性onInput
应用于要大写的<input />
元素。
import React, { useState } from "react";
import ReactDOM from "react-dom";
const toInputUppercase = e => {
e.target.value = ("" + e.target.value).toUpperCase();
};
const App = () => {
const [name, setName] = useState("");
return (
<input
name={name}
onChange={e => setName(e.target.value)}
onInput={toInputUppercase} // apply on input which do you want to be capitalize
/>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
希望它对您有用。
答案 4 :(得分:0)
您只需将此属性添加到输入字段中即可:
onInput={(e) => e.target.value = ("" + e.target.value).toUpperCase()}
希望它能起作用:)