1

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

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

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

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

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 个架构属性

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

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();
    }

    // ...
}
4

2 回答 2

0

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

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

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

我真的不认为这两个例子是矛盾的,因为它们完全不同。此外,单一职责原则中没有规定您不能从道具设置状态,您只需要注意您正在执行的上下文。

于 2018-05-31T21:53:32.470 回答
0

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

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

大多数时候,这种欺骗道具的反模式可以通过 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 类中的方法或使用 => 语法,以便可以使用 this 调用它们。

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

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

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

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

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

在一个单独的基于 React 的方法中,如果你有一些父母需要注意的事情,将代码的那部分“提升”到父母,反之亦然,将它作为道具绑定到孩子,例如 AJAX 函数调用 API。我认为它试图使组件尽可能地愚蠢

父项成为您“解除”项目的“事实来源”。父级处理更新,然后将结果传递给子级。因此,在父对象中,它可能作为状态变量存在,然后作为道具传递给子对象,然后子对象将其作为道具传递给它的子对象等。子对象会随着状态在父对象中的变化而更新它作为道具通过链向下传播。

如果您的应用程序仅是 React,即没有存储管理对象(例如通量模式或 redux 模式)的存储,则您可能必须将内容存储在最顶层的对象状态中,这在技术上可能被视为坏事。随着系统变得越来越复杂,flux 或 redux 的部分会更好地处理此功能。

希望这可以帮助!

于 2018-05-31T23:59:03.833 回答