Перейти к содержимому
шпаргалка.
Esc
навигацияоткрыть⌘Jпредпросмотр
На этой странице

Состояние и пропсы

Все темы React Developer

Что такое “состояние” (state) компонента в React?

Состояние хранит данные компонента между рендерами. В классовом компоненте state является объектом; значение состояния, созданного useState, может иметь любой тип.

В классовом компоненте состояние задают в constructor или поле state и обновляют через setState. В функциональном используют useState или useReducer. Обновление ставится в очередь; новое значение доступно следующему рендеру.

Пример:

import React, { Component } from "react";

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0, // Начальное состояние
    };
  }

  increment = () => {
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return (
      <div>
        <p>Счетчик: {this.state.count}</p>
        <button onClick={this.increment}>Увеличить</button>
      </div>
    );
  }
}

export default Counter;

В этом примере компонент Counter имеет состояние count, которое обновляется при клике на кнопку. При вызове setState(), React обновит состояние и перерендерит компонент, отображая новое значение count.


Как обновить состояние компонента?

В классовом компоненте setState принимает объект обновлений или функцию от предыдущего состояния и поверхностно объединяет результат со state. В функциональном компоненте setter из useState принимает следующее значение или функцию от предыдущего значения и заменяет его целиком. Состояние нельзя изменять напрямую.

Пример использования setState():

import React, { Component } from "react";

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
  }

  increment = () => {
    // Обновление состояния с использованием объекта
    this.setState({ count: this.state.count + 1 });
  };

  decrement = () => {
    // Обновление состояния с использованием функции
    this.setState((prevState) => {
      return { count: prevState.count - 1 };
    });
  };

  render() {
    return (
      <div>
        <p>Счетчик: {this.state.count}</p>
        <button onClick={this.increment}>Увеличить</button>
        <button onClick={this.decrement}>Уменьшить</button>
      </div>
    );
  }
}

export default Counter;

В данном примере increment() и decrement() обновляют состояние count с помощью setState(). Важно использовать функции при обновлении состояния, особенно если новое состояние зависит от предыдущего состояния, чтобы избежать проблем с асинхронностью.


Что такое пропсы (props) в React?

“Пропсы” (props) в React - это механизм передачи данных от родительского компонента к дочернему. Они представляют собой атрибуты, которые задаются при создании компонента и не могут быть изменены самим компонентом, который их получает. Пропсы используются для передачи информации о состоянии или конфигурации компонента.

Пример использования пропсов:

import React from "react";

function Welcome(props) {
  return <h1>Привет, {props.name}!</h1>;
}

const App = () => {
  return <Welcome name="Алиса" />;
};

export default App;

В этом примере компонент Welcome принимает пропс name и использует его для вывода персонализированного приветствия. Компонент App передает значение “Алиса” в пропс name компонента Welcome.

Пропсы передаются в виде объекта и доступны как свойства (props) внутри дочернего компонента.

Использование пропсов позволяет создавать более гибкие и переиспользуемые компоненты, так как можно настраивать их поведение и отображение извне.


В чем разница между состоянием и пропсами?

Состояние (state) и пропсы (props) - это два основных концепта в React, используемые для управления данными в компонентах. Они имеют разные цели и характеристики:

Состояние ( state ):
  1. Состояние - это внутренние данные компонента, которые могут изменяться во время выполнения.

  2. Определяется и управляется самим компонентом, в котором оно находится.

  3. Изменение состояния вызывает перерендеринг компонента, чтобы отобразить новое состояние.

  4. Доступно только для компонента, в котором было определено состояние.

  5. Обновляется через setState в классе, setter из useState или dispatch из useReducer в функциональном компоненте.

Пропсы ( props ):
  1. Пропсы - это данные, передаваемые от родительского компонента к дочернему компоненту.

  2. Нельзя изменить пропсы внутри дочернего компонента. Они считаются “только для чтения”.

  3. Пропсы служат для настройки и передачи данных в компоненты.

  4. Используются для связи между различными компонентами и передачи информации вниз по иерархии.

  5. При рендере родителя дочерний компонент обычно рендерится с новыми пропсами. memo может пропустить рендер, если пропсы не изменились.

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


Как обновить состояние компонента после изменения props?

В React существует несколько способов обновления состояния компонента после изменения его props. Это может потребоваться, когда компонент зависит от входящих props и должен реагировать на их изменения. Вот несколько подходов:

  1. componentDidUpdate(prevProps) : Метод componentDidUpdate()  вызывается после обновления компонента. Вы можете сравнить предыдущие и текущие props с помощью параметра prevProps и  this.props, и при необходимости обновить состояние:

    componentDidUpdate(prevProps) {
      if (this.props.someProp !== prevProps.someProp) {
        this.setState({ someState: newValue });
      }
    }
  2. getDerivedStateFromProps(nextProps, prevState) : Этот статический метод вызывается перед рендерингом и каждый раз, когда происходит обновление props. Вы можете вернуть новое состояние на основе новых props:

    static getDerivedStateFromProps(nextProps, prevState) {
      if (nextProps.someProp !== prevState.prevPropValue) {
        return { someState: newValue };
      }
      return null;
    }
  3. useState с useEffect : Если вы используете функциональные компоненты, вы можете использовать useState для хранения состояния и  useEffect для реагирования на изменения props:

    import React, { useState, useEffect } from "react";
    
    function MyComponent(props) {
      const [state, setState] = useState(initialState);
    
      useEffect(() => {
        if (props.someProp !== state.someState) {
          setState({ someState: newValue });
        }
      }, [props.someProp]);
    
      //...
    }

Не копируйте props в state без необходимости: вычисляйте производные значения во время рендера. Для полного сброса состояния можно изменить key компонента. getDerivedStateFromProps нужен лишь в редких случаях; Effect предназначен прежде всего для синхронизации с внешними системами. Примеры выше схематичны: initialState и newValue должны быть определены, а отслеживаемое предыдущее значение пропса нужно обновлять вместе с состоянием.


Как передать данные между компонентами вверх и вниз по иерархии?

В React данные могут передаваться между компонентами вверх и вниз по иерархии с использованием пропсов (props) и колбэков (callback функций). Вот как это работает:

Передача данных вниз по иерархии (от родителя к дочернему компоненту):

  1. Пропсы (props): Родительский компонент передает данные своему дочернему компоненту через пропсы. Дочерний компонент может получить доступ к этим данным как свойства (props).

Пример:

// Родительский компонент
import React from "react";
import ChildComponent from "./ChildComponent";

const ParentComponent = () => {
  const data = "Данные для дочернего компонента";

  return <ChildComponent dataProp={data} />;
};

// Дочерний компонент
import React from "react";

const ChildComponent = (props) => {
  return <p>{props.dataProp}</p>;
};

export default ChildComponent;

Передача данных вверх по иерархии (от дочернего компонента к родителю):

  1. Колбэки (callback функции): Родительский компонент передает функцию в качестве пропса дочернему компоненту. Дочерний компонент может вызвать эту функцию, передавая ей данные обратно вверх по иерархии.

Пример:

// Родительский компонент
import React, { useState } from "react";
import ChildComponent from "./ChildComponent";

const ParentComponent = () => {
  const [receivedData, setReceivedData] = useState("");

  const handleDataChange = (data) => {
    setReceivedData(data);
  };

  return (
    <div>
      <p>Полученные данные: {receivedData}</p>
      <ChildComponent onDataChange={handleDataChange} />
    </div>
  );
};

// Дочерний компонент
import React from "react";

const ChildComponent = (props) => {
  const sendDataToParent = () => {
    props.onDataChange("Данные от дочернего компонента");
  };

  return <button onClick={sendDataToParent}>Отправить данные</button>;
};

export default ChildComponent;

Это позволяет дочернему компоненту воздействовать на данные и состояние родительского компонента.

Используя этот подход, вы можете эффективно передавать и обновлять данные между компонентами вверх и вниз по иерархии.


Что такое “подъем состояния” (lifting state up)?

“Подъем состояния” (lifting state up) - это паттерн в React, который предполагает перемещение состояния из дочерних компонентов в родительские компоненты, чтобы разделять и управлять состоянием на более высоком уровне и передавать его через пропсы.

Этот подход особенно полезен, когда несколько компонентов должны иметь доступ к одному и тому же состоянию или когда состояние должно быть синхронизировано между разными частями приложения.

Пример с подъемом состояния:

import React, { useState } from "react";

const TemperatureInput = ({ scale, temperature, onTemperatureChange }) => {
  return (
    <fieldset>
      <legend>Введите температуру в градусах {scale}:</legend>
      <input
        value={temperature}
        onChange={(e) => onTemperatureChange(e.target.value)}
      />
    </fieldset>
  );
};

const Calculator = () => {
  const [celsius, setCelsius] = useState("");
  const [fahrenheit, setFahrenheit] = useState("");

  const handleCelsiusChange = (value) => {
    setCelsius(value);
    setFahrenheit((value * 9) / 5 + 32);
  };

  const handleFahrenheitChange = (value) => {
    setFahrenheit(value);
    setCelsius(((value - 32) * 5) / 9);
  };

  return (
    <div>
      <TemperatureInput
        scale="C"
        temperature={celsius}
        onTemperatureChange={handleCelsiusChange}
      />
      <TemperatureInput
        scale="F"
        temperature={fahrenheit}
        onTemperatureChange={handleFahrenheitChange}
      />
    </div>
  );
};

export default Calculator;

В этом примере компонент Calculator поднимает состояние температур из TemperatureInput компонентов. При изменении температуры в одном из вводов, состояние поднимается в родительский компонент Calculator, который затем обновляет состояние для другого ввода, обеспечивая синхронизацию температур в обеих шкалах.


Что такое “нормализация состояния” (state normalization) в контексте управления состоянием приложения?

Нормализация состояния (state normalization) - это паттерн управления состоянием, который используется для организации данных в хранилище таким образом, чтобы обеспечить эффективное хранение, обновление и доступ к данным в Redux или других системах управления состоянием.

Основная идея нормализации состоит в том, чтобы хранить данные в нормализованной форме, где каждый тип данных хранится в отдельной коллекции (таблице), и используются ссылки между различными коллекциями для устранения дублирования данных и облегчения обновления.

Пример: Предположим, у нас есть список постов и список комментариев к этим постам. Вместо хранения комментариев внутри каждого поста (что может привести к дублированию данных), мы можем создать две коллекции: “посты” и “комментарии”, и использовать идентификаторы постов в комментариях для установления связи между ними.

Преимущества нормализации состояния:

  1. Экономия места: Дублирование данных уменьшается, так как одни и те же данные не хранятся в нескольких местах.

  2. Легкость обновления: Изменение данных в одной коллекции автоматически отражается в других, где эти данные используются.

  3. Быстрый доступ: Поиск, фильтрация и доступ к данным ускоряются, так как данные разделены на более мелкие коллекции.

  4. Прозрачность: Структура хранилища становится более легко понимаемой и отслеживаемой.

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


Как управлять состоянием между компонентами, не имеющими близкой связи?

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

  1. Поднятие состояния ( Lifting State Up ): Вы можете поднять состояние до ближайшего общего родительского компонента, который имеет доступ и к одному, и к другому компоненту. Затем передавайте это состояние как пропсы в каждый компонент. Этот подход особенно полезен, когда компоненты имеют общий родительский компонент, но не имеют прямой связи друг с другом.

  2. Контекст ( Context API ): Используйте Context API, который позволяет передавать данные глубоко в дерево компонентов без явной передачи пропсов через все уровни. Создайте контекст и оберните ваше дерево компонентов этим контекстом. Таким образом, компоненты смогут получать доступ к данным из контекста, даже если они не находятся в прямой иерархии.

  3. Глобальное состояние ( Global State ): Используйте библиотеки управления состоянием, такие как Redux или MobX, чтобы создать глобальное хранилище данных, доступное для всех компонентов. Это особенно полезно, если состояние нужно между компонентами, которые находятся далеко друг от друга в дереве компонентов.

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

  5. RESTful API: Если ваши компоненты общаются с сервером, вы можете использовать RESTful API для обмена данными между ними. Компоненты могут получать и отправлять данные через API.

  6. Библиотеки для управления состоянием: В зависимости от вашего опыта и требований, вы также можете рассмотреть использование библиотек управления состоянием, таких как Recoil, Zustand и других.

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

Эта страница была полезной?