Как мне обрабатывать состояние компонента в соответствии с шаблоном единой ответственности

Я новичок в ReactJs и стараюсь следовать лучшим практикам. Из моего исследования я наткнулся на пару противоречащих друг другу статей, в которых обсуждается, какой должна быть реализация.

Должно ли состояние полагаться на свойства, передаваемые от родительского компонента? В приведенных ниже сравнениях они оба следуют SRP, но не уверены, какой из них лучше. Хотелось бы вашего совета, спасибо!

1. -- Рекомендации для состояния компонента в 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 архитектурных атрибутов надежного React компонент

Давайте рефакторинг возьмем на себя одну обязанность: визуализировать поля формы и прикрепить обработчики событий. Он не должен знать, как использовать хранилище напрямую..... Компонент получает сохраненное входное значение из prop initialValue и сохраняет входное значение, используя функцию prop saveValue(newValue). Эти реквизиты предоставляются withPersistence() HOC с использованием техники прокси реквизитов.

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

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

3. -- В моем случае у меня есть что-то вроде следующего (интересно, является ли это приемлемой реализацией?) -- Должно ли состояние обрабатываться в задачах или в другом компоненте типа TasksWithPersistence, который находится между TasksWithData и Tasks?

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

    // ...
}

person briang    schedule 31.05.2018    source источник
comment
Помогает ли этот ответ? stackoverflow.com/questions/40063468/ Как ученик я избегаю установки состояния в конструкторе. Обычно я использую их напрямую, не привлекая государство. Если вам действительно нужно изменить эти реквизиты и удерживать их в состоянии, возможно, вы можете сделать это componentDidMount.   -  person devserkan    schedule 31.05.2018
comment
Спасибо, но не совсем то, что я надеялся получить от него. Я следую примеру первого класса из этого поста. В приведенных выше примерах они этого не делают, но концепция та же. Меня больше беспокоит, должен ли дочерний компонент устанавливать состояние, в моем случае, в методе жизненного цикла componentDidMount с передаваемыми реквизитами или это нет-нет.   -  person briang    schedule 31.05.2018
comment
Если вам нужно, вы можете установить состояние в Child. Но если вам не нужно изменять его реквизиты и использовать их локально в состоянии, не завися от родителя, зачем вам нужно использовать состояние? Ситуация такая: если вы не мутируете реквизиты, не устанавливайте их в своем состоянии, даже не используйте компонент на основе состояния или класса, если вам не нужно какое-либо состояние или жизненный цикл в вашем дочернем компоненте. Вот как я поступаю как ученик, как и вы.   -  person devserkan    schedule 31.05.2018
comment
Я добавил к своему первоначальному вопросу (см. № 3) --- Согласен, если состояние не нужно менять, просто используйте реквизит и забудьте об установке состояния.   -  person briang    schedule 31.05.2018
comment
Здесь вы используете HOC, поэтому кажется, что его единственная обязанность — передача данных. Возможно, обработка состояния в Tasks — это правильная ситуация. По крайней мере, я бы так поступил. Но, опять же, я какой-то новичок, дополнительные предложения приветствуются :)   -  person devserkan    schedule 31.05.2018


Ответы (2)


Суть вашего вопроса, кажется, вращается вокруг анти-шаблон, который берет некоторые реквизиты и дублирует их в состояние. Это, видоизменение реквизита, не является целью государства. Реквизиты неизменны, оболванивание их до состояния побеждает этот дизайн.

Целью состояния является управление вещами, специфичными для компонента 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 вам необходимо связать методы в вашем классе реакции в конструкторе или используйте синтаксис =>, чтобы их можно было вызывать с помощью this.

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

Вы также можете разложить соответствующие части на новый компонент с именем FullName, если он будет использоваться несколькими компонентами.

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

Технически «способ реагирования» — это, по крайней мере, по мнению этого автора, разложение этого на другой компонент для повторного использования. Однако повторное использование компонентов необходимо сопоставлять с добавленной сложностью, то есть не оптимизируйте преждевременно. Поэтому поначалу вы можете не заходить слишком далеко. Времена, когда это необходимо, возникнут сами собой.

Очень широкое обобщение реквизитов React состоит в том, что они гарантированы, неизменны и стекают, как водопад, с самого верхнего компонента. Если вам нужно обновить их, обновите их на самом высоком уровне, где это имеет смысл.

В подходе, основанном на единственном React, если у вас есть что-то, о чем должен знать родитель, «поднимите» эту часть кода до родителя и, наоборот, привяжите ее к дочернему элементу в качестве реквизита, например. функция AJAX, которая вызывает API. Я думаю об этом как о попытке сделать компоненты настолько тупыми, насколько это возможно.

Родитель становится «источником правды» для предмета, который вы «подняли». Родитель обрабатывает обновления, а затем передает результаты дочерним элементам. Таким образом, в родительском объекте он может существовать как переменная состояния, а затем передаваться в качестве реквизита дочернему объекту, который затем передает его в качестве реквизита своему дочернему объекту и т. д. Дети будут обновляться по мере изменения состояния в их родительском объекте, когда он распространяется вниз по цепочке в качестве реквизита.

Если ваше приложение предназначено только для React, т. е. без хранилищ, которые управляют объектами, такими как шаблон потока или шаблон сокращения, вам, возможно, придется хранить вещи в самом верхнем состоянии объекта, которое технически может рассматриваться как плохое. По мере того, как ваша система становится более сложной, эта функциональность будет лучше обрабатываться частями Flux или Redux.

Надеюсь это поможет!

person engineerDave    schedule 31.05.2018
comment
Спасибо за ответ! Вы упомянули, что я пришел из Ruby на основе подчеркивания, которое я не включил ни в одну часть этого примера (не уверен, что вы скопировали откуда-то еще), но нет, я никогда не работал с Ruby. Я ценю дополнительную информацию и основу методологий React. - person briang; 01.06.2018
comment
просто предположение, поскольку ruby ​​— один из немногих популярных языков с синтаксисом подчеркивания для переменных, но ни в коем случае не единственный. GLHF с реакцией! :) - person engineerDave; 01.06.2018
comment
Благодарность! Из любопытства, где вы видели символы подчеркивания в именах моих переменных? Возможно, я слишком долго смотрел на свой код, лол. - person briang; 01.06.2018
comment
ОМГ ты прав. Я виню полуденный мозг. Я, должно быть, имел в виду другую проблему, когда писал это! ха-ха - person engineerDave; 01.06.2018

Между примерами 1 и 2 огромная разница.

В примере № 1 причина, по которой нельзя устанавливать состояние из этих реквизитов таким образом, заключается в том, что если реквизиты изменятся, виджет не будет обновляться. Лучшие практики или нет, это просто неправильно и плохо в любой среде. В этом конкретном случае действительно нет смысла даже использовать состояние. Достаточно будет одного реквизита.

В примере № 2 свойство используется только для присвоения состоянию начального значения (у свойства даже есть имя initialValue), подразумевая, что дальнейшие изменения состояния будут контролироваться компонентом независимо от изменений свойств. Использование реквизита для начального состояния не нарушает принцип единой ответственности, особенно когда он явно используется для этой цели.

Я действительно не считаю эти два примера противоречащими друг другу, потому что они совершенно разные. Кроме того, в принципе единой ответственности нет правила, согласно которому вы не можете установить состояние из реквизита, вам просто нужно обратить внимание на контекст, в котором вы это делаете.

person Pop-A-Stash    schedule 31.05.2018
comment
Спасибо! Я полагаю, что нашел их противоречивыми из-за настройки состояния по свойствам, что и было основной целью моего вопроса. Я вижу одно направление, где говорят, что свойства не должны устанавливать состояние, но затем я вижу другое, где это происходит. - person briang; 01.06.2018