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

时间:2018-05-31 18:44:47

标签: reactjs single-responsibility-principle react-component

我是ReactJs的新手,并试图遵循最佳做法。从我的研究中,我发现了一些讨论如何实施的矛盾文章。

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

1。 - Best Practices for Component State in React.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。 - 7 architectural attributes of a reliable React component

  

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

class PersistentForm extends Component {  
    constructor(props) {
        super(props);

        this.state = { inputValue: props.initialValue };
    }
    // ...
}

3。 - 就我而言,我有类似下面的内容(想知道这是否是可接受的实现?) - 应该在Tasks中处理状态,还是在TasksWithData和Tasks之间的另一个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();
    }

    // ...
}

2 个答案:

答案 0 :(得分:0)

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

在示例#1中,以这种方式从那些道具设置状态是不好的原因是如果道具改变,窗口小部件将不会更新。最佳实践与否,在任何框架中都是错误的和坏的。在那种特殊情况下,即使使用国家也没有意义。只有道具就足够了。

在示例#2中,prop仅用于为状态赋予初始值(prop甚至命名为initialValue),这意味着无论prop变化如何,组件都将控制对状态的进一步更改。对于初始状态使用道具不会违反单一责任原则,特别是当它明确用于此目的时。

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

答案 1 :(得分:0)

您的问题的要点似乎围绕anti-pattern围绕着采取一些道具并将其复制到。这种道具的变异不是国家的目的。道具是不可改变的,重复他们到国家失败这个设计。

状态的目的是管理特定于React组件的东西,即仅限于该React组件的范围。例如,showHide开关用于在React组件中显示的内容。如果它有帮助,可以将状态视为本地范围的变量。

大多数情况下,重复道具的这种反模式可以通过React对象中的函数来满足。例如,state.full_name变量成为命名函数fullName,绑定到React Component。 (所有代码示例都假设是JSX语法)

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

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

然后可以在组件的渲染中调用该函数

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

注意:请记住,在ES6中,您必须在构造函数中使用bind the methods in your react class或使用=&gt;语法,以便您可以使用它来调用它们。

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

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

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

从技术上讲,“反应方式”至少在本作者看来,将其分解为另一个可重用性的组件。但是,需要根据所添加的复杂性来权衡组件重用,即不要过早地进行优化。所以你可能不想一开始就把它拿得太远。有必要的时间会自然而然地出现。

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

在一个基于反应的基于反应的方法中,如果你有一些父母需要注意的东西,“将”代码的那部分提升到父母,反之亦然,将其作为道具将其绑定到孩子身上,例如一个调用API的AJAX函数。我认为它是尽可能地将组件保持为 dumb

父母成为你“解除”项目的“真相来源”。父级处理更新,然后将结果传递给子级。因此在父级中,它可以作为状态变量存在,然后作为props传递给子对象,然后将子对象作为道具传递给它的子对象等。当子状态在其父级中发生更改时,子级将更新它通过链传播作为道具。

如果你的应用程序只是React,即没有管理对象的商店,例如在flux模式或redux模式中,你可能必须将事物存储在最顶层的objet状态,从技术上讲可能被视为坏。随着您的系统变得越来越复杂,flux或redux的部件可以更好地处理这个功能。

希望这有帮助!