我应该如何处理遵循单一责任模式的组件状态



我是ReactJs的新手,并试图遵循最佳实践。从我的研究中,我遇到了几篇相互矛盾的文章,讨论应该如何实施。

状态是否应该依赖于从父组件传递的属性?在下面的比较中,他们都遵循SRP,但不确定哪个是最好的。想要您的建议,谢谢!

1. -- 反应中组件状态的最佳实践.js

首先,也可能是最重要的,组件的状态不应该依赖于传入的道具。(请参阅下面的示例,了解我们不应该做的事情)

class UserWidget extends React.Component {
// ...
// BAD: set this.state.fullName with values received through props
constructor (props) {
this.state = {
fullName: `${props.firstName} ${props.lastName}`
};
}
// ...
}

2. -- 可靠 React 组件的 7 个架构属性

让我们重构为一个职责:呈现表单字段并附加事件处理程序。它不应该知道如何直接使用存储.....组件从 prop initialValue 接收存储的输入值,并使用 prop 函数 saveValue(newValue) 保存输入值。这些 props 由 withPersistence() HOC 使用 props 代理技术提供。

class PersistentForm extends Component {  
constructor(props) {
super(props);
this.state = { inputValue: props.initialValue };
}
// ...
}

3. -- 就我而言,我有类似以下内容的内容(想知道这是否是一个可接受的实现?) - 状态应该在任务中处理,还是在位于 TasksWithData 和任务之间的另一种 TasksWithPersistence 类型的组件中处理?

export default function TasksWithData(TasksComponent) {  
return class withData extends React.Component {
render() {
const tasks = TaskAPI.getTasks();
return (
<TasksComponent 
tasks={tasks} 
{...this.props} 
/>
)
}
}
}

export default class Tasks extends React.Component {
state = { 
tasks: [], 
addItemInput: null 
};
// ...
componentDidMount() {
this.updateComponentState({tasks: this.props.tasks});
}
componentDidUpdate() {
this.prepUIForNextAddition();
}
// ...
}

你问题的要点似乎围绕着反模式,即采取一些道具并将其复制到状态中。这,道具的变异,不是国家的目的。道具是不可变的,将它们欺骗给国家会挫败这种设计。

状态的目的是管理特定于 React 组件的东西,即严格限定为该 React 组件。例如,一个 showHide 开关,用于在 React 组件中显示某些内容。如果有帮助,请将状态视为局部范围的变量。

大多数时候,这种重复道具的反模式可以通过 React 对象中的函数来满足。例如,你的state.full_name变量变成了一个命名函数 fullName,绑定到 React 组件。(所有代码示例都假定 JSX 语法)

注意:在 JavaScript 中,驼峰是函数和变量的命名结构,我假设你来自基于下划线命名约定的 ruby。IMO 最好坚持编写代码时使用的语言的约定。这就是我使用驼峰命名的原因。

...
fullName() {
return this.props.firstName + " " + this.props.lastName
} 
...

然后可以在组件的呈现中调用该函数

# in render() portion of your React component, assuming jsx syntax
<p>Hello, {this.fullName()}</p>

注意:请记住,在 ES6 中,您必须在构造函数中绑定 react 类中的方法或使用 => 语法,以便您可以使用它调用它们。

...
constructor(props) {
super(props);
this.fullName = this.fullName.bind(this);
}
...

如果多个组件将使用该组件,您还可以将相关部分分解为名为FullName的新组件。

<FullName firstName={this.props.firstName} lastName={this.props.lastName} />

从技术上讲,"反应方式"至少在作者看来是将其分解为另一个组件以实现可重用性。但是,组件重用需要与增加的复杂性进行权衡,即不要过早优化。因此,一开始您可能不想走得太远。必要的时候会自然而然地出现。

对 React 道具的一个非常广泛的概括是,它们是有保证的,是不可变的,它们像瀑布一样从最顶层的组件流下来。如果需要更新它们,请在有意义的最高级别更新它们。

在基于 soley React 的方法中,如果你有一些父级需要注意的东西,请将这部分代码"提升"到父级,反之亦然,将其作为 props 绑定到子级,例如调用 API 的 AJAX 函数。我认为这是试图使组件尽可能愚蠢

父母成为你"举起"的物品的"真相来源"。父级处理更新,然后将结果传递给子级。因此,在父对象中,它可能作为状态变量存在,然后作为 props 传递给子对象,然后子对象将其作为 props 传递给它的子对象,等等。当状态作为道具通过链向下传播时,子项将随着其父级中的状态发生变化而更新。

如果你的应用程序只是 React 的,即没有管理对象的商店,例如在 flux 模式或 redux 模式中,你可能不得不将东西存储在最顶层的 objet 状态,这在技术上可能被视为糟糕的。随着您的系统变得越来越复杂,此功能最好由 flux 或 redux 的部件来处理。

希望这有帮助!

示例 1 和示例 2 之间存在巨大差异。

在示例 #1 中,以这种方式从这些 props 设置状态是不好的原因是,如果 props 发生变化,小部件将不会更新。无论是否最佳实践,这在任何框架中都是错误和糟糕的。在这种特殊情况下,即使使用状态也确实没有意义。仅道具就足够了。

在示例 #2 中,prop 仅用于给状态一个初始值(prop 甚至被命名为initialValue),这意味着无论 prop 如何更改,对状态的进一步更改都将由组件控制。 将 props 用于初始状态并不违反单一责任原则,尤其是当它明确用于该目的时。

我真的不认为这两个例子是矛盾的,因为它们是完全不同的。此外,单一责任原则中没有规则不能从 props 设置状态,你只需要注意你这样做的上下文。

最新更新