我可以在 React 组件中解耦布尔状态吗
Posted
技术标签:
【中文标题】我可以在 React 组件中解耦布尔状态吗【英文标题】:Can I decouple boolean state in React component 【发布时间】:2021-04-28 10:17:04 【问题描述】:如下简单的反应组件代码:
class Test extends React.Component
constructor(props)
super(props)
this.c1 = this.c1.bind(this);
this.c2 = this.c2.bind(this);
this.state =
a:false,
b:false
c1(e)
this.setState(a:true, b:false)
c2(e)
this.setState(a:false, b:true)
render()
return (
<div>
<div>
<input name="n" type="radio" onChange=this.c1 />
<input name="n" type="radio" onChange=this.c2 />
</div>
<div>
this.state.a && "aa"
this.state.b && "bb"
</div>
</div>
)
代码只是在单击单选按钮时切换显示“aa”或“bb”。但是,如果我添加一个显示“cc”的新单选按钮来实现相同的功能。我应该:
-
添加新状态,如“c”
添加新的输入 html 并实现其回调
此回调中的 setState 'c'
所有这些都可以,但是我必须更改 'c1','c2' 函数,使我的代码耦合如下:
class Test extends React.Component
constructor(props)
super(props)
this.c1 = this.c1.bind(this);
this.c2 = this.c2.bind(this);
this.c3 = this.c3.bind(this);
this.state =
a:false,
b:false,
c:false,
c1(e)
this.setState(a:true, b:false, c:false) // add 'c:false' which coupled
c2(e)
this.setState(a:false, b:true, c:false) // add 'c:false' which coupled
c3(e)
this.setState(a:false, b:false, c:true)
render()
return (
<div>
<div>
<input name="n" type="radio" onChange=this.c1 />
<input name="n" type="radio" onChange=this.c2 />
<input name="n" type="radio" onChange=this.c3 />
</div>
<div>
this.state.a && "aa"
this.state.b && "bb"
this.state.c && "cc"
</div>
</div>
)
我认为这种情况在 React 中很常见。所以无论我添加多少单选按钮,我都想解耦我的代码。我不需要更改代码,只需添加代码即可满足“开闭原则”。
你有什么建议吗?提前致谢。
【问题讨论】:
看起来 *** question 可能是您要找的 (?) 感谢@DorWeid,这是关于设计模式,而不是关于如何使用单选按钮。 【参考方案1】:我认为你可以这样做
class Test extends React.Component
constructor(props)
super(props)
this.change = this.change.bind(this);
this.state =
a:false,
b:false,
c:false,
change = statename => e =>
this.setdefault();
this.setState(
[statename]: true
);
;
setdefault()
this.setState(
a:false,
b:false,
c:false,
);
render()
return (
<div>
<div>
<input name="n" type="radio" onChange=this.change("a") />
<input name="n" type="radio" onChange=this.change("b") />
<input name="n" type="radio" onChange=this.change("c") />
</div>
<div>
this.state.a && "aa"
this.state.b && "bb"
this.state.c && "cc"
</div>
</div>
)
【讨论】:
【参考方案2】:鉴于属性是相互依赖的而不是独立的,我觉得将状态存储为键控 boolean
值的方式不合适。
现在,state
有四个选项:
a:false, b:false, c:false // initial state from constructor
a:true, b:false, c:false // from c1
a:false, b:true, c:false // from c2
a:false, b:false, c:true // from c3
根据您的 setState
回调,一次不能超过 1 个属性为 true
。
如果每个属性都是独立的,那么您将有 8 个选项 (2^3),并且这种设置是有意义的。
事实上,我建议您只存储哪个值是true
。您可以通过查看单个选项是否与存储的 selected
值匹配来检查单个选项是否为 true
。
无论有多少按钮,您都希望Component
工作,所以让我们将按钮选项传递为props
。就设计模式而言,这就是“依赖注入”。我们可以创建一个SelectOne
,它不需要知道它的选项是什么。在这里,我只是希望 options
是 string
,例如 "aa"
或 "bb"
,但您可以将其重构为具有属性 label
和 value
的 object
。
我们要循环遍历options
的array
并渲染每一个。有时您会看到它被提取到组件的方法中,例如 this.renderOption(i)
,但您也可以在 render()
中进行内联映射。
您实际上并未在回调中使用事件e
。您可以使用该事件来获取e.target.value
,假设您在输入中设置了 value 属性(有关 HTML 标记,请参阅MDN docs)。您还可以通过为onChange
创建一个匿名箭头函数将值传递给回调,该函数使用正确的值调用它。我正在这样做。
这里它作为一个类组件,因为这是你以前使用的。
class SelectOne extends React.Component
constructor(props)
super(props);
this.state =
selected: undefined // this.state.selected will initially be undefined
render()
return (
<div>
<div>
this.props.options.map((optionName) => (
<label htmlFor=optionName>
optionName
<input
type="radio"
id=optionName
name="n"
value=optionName
checked=this.state.selected === optionName
onChange=() => this.setState(selected: optionName)
/>
</label>
))
</div>
this.state.selected !== undefined && (
<h2>Selected: this.state.selected</h2>
)
</div>
);
这里是作为一个函数组件。这是较新的语法,所以如果您只是在学习,那么我建议您使用函数组件和钩子来学习。销毁 props 可以很容易地接受可选的 props 并设置它们的默认值。我允许在此处传递input
的name
属性,但如果未提供,则默认为您的"n"
。
const SelectOne = (options, name = "n") =>
// will be either a string or undefined
const [selected, setSelected] = React.useState(undefined);
return (
<div>
<div>
options.map((optionName) => (
<label htmlFor=optionName>
optionName
<input
type="radio"
id=optionName
name=name // from props
value=optionName
checked=selected === optionName
onChange=() => setSelected(optionName)
/>
</label>
))
</div>
selected !== undefined && (
<h2>Selected: selected</h2>
)
</div>
);
无论哪种方式,您都可以这样称呼它:
<SelectOne options=["aa", "bb", "cc"] />
您还可以为给定的options
集合创建一个特定的组件,您现在可以在没有道具的情况下调用它。
const SelectABC = () => <SelectOne options=["aa", "bb", "cc"] />;
<SelectABC/>
【讨论】:
以上是关于我可以在 React 组件中解耦布尔状态吗的主要内容,如果未能解决你的问题,请参考以下文章