tl;drReact 拒绝兑现checked={checkThisOption}
在输入上,即使它尊重data-ischecked={checkThisOption}
完全在同一组输入上。
我还没有在 jsfiddle 上完成这项工作,但我已经使用重现了这个问题这段代码 https://gist.github.com/tomprogers/54e70947c4b95b60a7aa.
长版
我有一个简单的 ReactJS 组件,它向用户显示单选按钮列表。用户应该能够选择收音机,然后按下按钮来确认他们的选择。
这是组件 def(注意:我使用的是 ES6 和 webpack):
import React from 'react';
class Widget extends React.Component {
constructor(props) {
super(props);
this.state = {
currentValue: null // tracks currently-selected choice, by its value
};
}
onClickOptionRadio = (event) => {
this.setState({
currentValue: String(event.currentTarget.value)
});
}
onConfirm = (event) => {
if(!this.props.onChange) return;
this.props.onChange(this.state.currentValue);
};
render() {
let choices = this.props.choices;
let currentValue = this.state.currentValue;
return (
<div className="Widget">
<ol className="choices">
{
choices.map((choice, i) => {
// decide whether to mark radio as checked:
// - if no current choice, check first radios
// - otherwise, check radio matching current choice
let noCurrentChoice = (currentValue === null);
let drawingFirstChoice = (i === 0);
let thisChoiceIsSelected = (String(choice.value) === currentValue);
let checkThisOption = thisChoiceIsSelected || (noCurrentChoice && drawingFirstChoice);
return (
<li key={i}>
<input type="radio" name="choices"
value={choice.value}
onChange={this.onClickOptionRadio}
checked={checkThisOption?'checked':''}
data-ischecked={checkThisOption}
/>
<label>{choice.label}</label>
{' '}
{checkThisOption ? 'CHECKED' : ''}
</li>
);
})
}
</ol>
<button onClick={this.onConfirm}>Confirm choice</button>
</div>
);
}
}
export default Widget;
这是所属组件:
import React from 'react';
import Widget from 'components/widget';
class Owner extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
let choices = [
{ value: 10, label: 'First' },
{ value: 20, label: 'Second' },
{ value: 30, label: 'Third' }
];
return (
<div className="Owner">
<Widget
choices={choices}
/>
</div>
);
}
}
export default Owner;
这是它的实际动图:
请注意视频中的几件事:
- 该逻辑显然适用于在初始渲染时检查第一个无线电
- 当用户点击其他无线电时,它们不会被选中
- 然而,该逻辑显然适用于识别选择了哪个项目,如
margin-right: 2rem
在应该检查的收音机上
- 指示已选择哪个选项的文本自始至终都是准确的
- 当我点击收音机时,
componentWillUpdate
方法仅针对 Widget 本身触发;它的祖先都没有更新
我认为这个演示证明这不是一个案例Widget
实例被状态为空的另一个实例替换。事实上,当前的选择准确地反映了data-
attr 在输入上以及纯文本,表明状态按预期持续存在。我确信这种不受欢迎的行为是设计使然,我想知道如何解决 React 应用于受控输入的表单相关属性的奇怪、异常的逻辑。
为什么我认为当前的行为是错误的?我不希望拥有组件知道每个单选按钮 - 所有者应该绑定到 Widget 的onChange
做出最终选择后通知的方法。
这是一个简化的示例。真正的组件更复杂,但原理是相同的:就像日期选择组件可能有许多其所属组件不知道的内部状态一样(例如要显示什么时间尺度,要显示哪一年、哪一个月或哪一周)显示等),该组件也有一些有趣的内部状态,拥有组件没有业务管理。
据我所知,我做得完全正确。该组件通过以下方式发布其重要的状态更新onChange(event, newValue)
,应该绑定到哪个拥有组件。我认为 React 很明显deciding不更新checked
这些输入上的 attr,即使它显然能够更新相同元素上的其他 attr 以响应相同的用户操作。
注意楼主不是现在聆听onChange
,但这并不重要:即使所有者没有在听,子组件也应该能够管理其自己的内部状态。我拒绝这样的说法,即无线电状态不能准确,只是因为所有者没有提供currentValue
via props:Widget 可以在没有该 prop 的情况下直接管理和渲染其状态。 React 必须做一些特殊的事情来防止checked
不按照适用的规则进行处理所有其他元素和属性。这是一个例外,我认为这是一个糟糕的例外。
最后,请注意,此问题似乎仅在该组件位于某个复合树深度以下时才会发生。当它是 Flux“页面”或 Redux“容器”中唯一的组件时,它的效果很好。当它嵌套得更深时,正如我所描述的那样,它会失败。我还没有想出一个简洁的方式来展示这一点。
任何建议表示赞赏。据我所知,React 违反了它自己规定的规则,我预计这种行为会阻碍构建其他围绕普通版本构建的有状态组件input
s.
Edit:我更正了生成的name
无线电,并更新了演示以反映它。向所有开始追寻这些东西的人道歉。