← Назад к вопросам

Что такое декларативность?

1.0 Junior🔥 111 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Декларативность vs Императивность: Основной принцип modern frontend

Декларативность — это парадигма программирования, где ты описываешь ЧТО ты хочешь получить, а не КАК это получить. Это фундаментальный принцип React и современного frontend разработки.

Декларативность (Declarative) vs Императивность (Imperative)

Пример 1: Обновление DOM

Императивный подход (как старый jQuery):

// Как получить результат?
const button = document.getElementById('toggle-button');
const message = document.getElementById('message');

button.addEventListener('click', () => {
  if (message.style.display === 'none') {
    message.style.display = 'block';
    message.textContent = 'Visible';
  } else {
    message.style.display = 'none';
    message.textContent = 'Hidden';
  }
});

Здесь ты пошагово указываешь браузеру, что нужно делать:

  1. Найти элемент по ID
  2. Добавить обработчик события
  3. Проверить текущее состояние
  4. Изменить style
  5. Изменить textContent

Декларативный подход (React):

// Что ты хочешь видеть?
export function ToggleMessage() {
  const [isVisible, setIsVisible] = useState(false);

  return (
    <div>
      <button onClick={() => setIsVisible(!isVisible)}>
        Toggle Message
      </button>
      {isVisible && <p>Visible</p>}
      {!isVisible && <p>Hidden</p>}
    </div>
  );
}

Здесь ты описываешь состояние и UI:

  • Если isVisible true, показывай "Visible"
  • Если isVisible false, показывай "Hidden"
  • React сам решает, как обновить DOM

Преимущества декларативности

1. Читаемость кода

// Декларативное: сразу понятна логика
function UserProfile({ user, isLoading, error }) {
  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;
  return <div>{user.name}</div>;
}

// Императивное: нужно читать весь код для понимания
function UserProfile({ user, isLoading, error }) {
  let element;

  if (isLoading) {
    element = document.createElement('div');
    element.textContent = 'Loading...';
  } else if (error) {
    element = document.createElement('div');
    element.textContent = `Error: ${error}`;
  } else {
    element = document.createElement('div');
    element.textContent = user.name;
  }

  return element;
}

2. Меньше ошибок

// Декларативное: React отслеживает зависимости
useEffect(() => {
  if (!isVisible) {
    startAnimation();
  }
}, [isVisible]); // React знает, что нужно пересчитать при изменении isVisible

// Императивное: легко забыть обновить логику
element.addEventListener('visibilitychange', () => {
  if (!isVisible) {
    startAnimation();
    // Что если isVisible изменилась? Нужно обновлять все места?
  }
});

3. Переиспользуемость

// Декларативный компонент легче переиспользовать
function Button({ onClick, disabled, children }) {
  return (
    <button onClick={onClick} disabled={disabled} className="btn">
      {children}
    </button>
  );
}

// Работает везде одинаково
<Button onClick={handleSubmit} disabled={isLoading}>
  Submit
</Button>

// Императивный код сложнее переиспользовать
const createButton = (id, handler, disabled) => {
  const btn = document.getElementById(id);
  btn.addEventListener('click', handler);
  btn.disabled = disabled;
  // Что если нужно создать несколько кнопок? Нужен цикл?
};

Примеры декларативности в React

Пример 1: Условный рендеринг

// Декларативное
export function UserCard({ user, isModerator }) {
  return (
    <div className="card">
      <h2>{user.name}</h2>
      {isModerator && <badge>Moderator</badge>}
      {user.verified && <checkmark />}
    </div>
  );
}

// Ясно видно, при каких условиях что рендерится

Пример 2: Списки

// Декларативное
export function TodoList({ items, filter }) {
  const filtered = items.filter((item) => {
    if (filter === 'active') return !item.completed;
    if (filter === 'completed') return item.completed;
    return true;
  });

  return (
    <ul>
      {filtered.map((item) => (
        <li key={item.id} className={item.completed ? 'done' : ''}>
          {item.text}
        </li>
      ))}
    </ul>
  );
}

// Сразу видно: описываем, какие items показываем и как их рендерим

Пример 3: Классы вместо методов

// Декларативное: используем классы для вычисления стиля
function Button({ variant = 'primary', size = 'md' }) {
  const baseClasses = 'px-4 py-2 rounded font-semibold transition';
  const variantClasses = {
    primary: 'bg-blue-500 text-white hover:bg-blue-600',
    secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300',
  };
  const sizeClasses = {
    sm: 'text-sm',
    md: 'text-base',
    lg: 'text-lg',
  };

  return (
    <button
      className={`${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]}`}
    >
      Click me
    </button>
  );
}

// Ясно видно все комбинации стилей

Когда нарушается декларативность

Нужно избегать смешивания декларативного и императивного кода:

// Плохо: смешивание императивности
function MessyComponent() {
  const [data, setData] = useState(null);
  const refContainer = useRef(null);

  useEffect(() => {
    // Декларативное
    fetchData().then(setData);

    // Но потом императивное манипулирование DOM
    if (refContainer.current) {
      refContainer.current.innerHTML = renderData(data);
      refContainer.current.classList.add('visible');
    }
  }, []);

  return <div ref={refContainer} />;
}

// Хорошо: чистая декларативность
function CleanComponent() {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetchData().then(setData);
  }, []);

  return (
    <div className={data ? 'visible' : 'hidden'}>
      {data && renderData(data)}
    </div>
  );
}

Декларативность в разных областях

CSS (декларативность вкуса)

// Декларативное: описываем состояния
const buttonClasses = cn(
  'px-4 py-2 rounded', // базовые стили
  isLoading && 'opacity-50 cursor-not-allowed', // loading состояние
  isError && 'bg-red-500 text-white', // error состояние
  isSuccess && 'bg-green-500 text-white' // success состояние
);

// Видно все возможные состояния кнопки

Queries и API

// Декларативное: React Query
const { data, isLoading, error } = useQuery({
  queryKey: ['users', id],
  queryFn: () => fetchUser(id),
});

// Описываем ЧТО нам нужно, Query сам решает КАК это получить

// Императивное
const [data, setData] = useState(null);
const [isLoading, setIsLoading] = useState(true);

useEffect(() => {
  setIsLoading(true);
  fetch(`/api/users/${id}`)
    .then((r) => r.json())
    .then(setData)
    .finally(() => setIsLoading(false));
}, [id]);

// Нужно вручную управлять загрузкой, ошибками, кешем

Практический пример: Form Handling

Императивный подход (контроль DOM):

function LoginForm() {
  const emailRef = useRef(null);
  const passwordRef = useRef(null);

  const handleSubmit = () => {
    const email = emailRef.current.value;
    const password = passwordRef.current.value;

    if (!email || !password) {
      alert('Please fill all fields');
      return;
    }

    // Вручную управляем состоянием
    emailRef.current.disabled = true;
    passwordRef.current.disabled = true;

    login(email, password)
      .then(() => {
        navigate('/dashboard');
        emailRef.current.value = '';
        passwordRef.current.value = '';
      })
      .catch((err) => {
        alert(err.message);
      })
      .finally(() => {
        emailRef.current.disabled = false;
        passwordRef.current.disabled = false;
      });
  };

  return (
    <form>
      <input ref={emailRef} type="email" />
      <input ref={passwordRef} type="password" />
      <button onClick={handleSubmit}>Login</button>
    </form>
  );
}

Декларативный подход (контроль состояния):

function LoginForm() {
  const [formData, setFormData] = useState({ email: '', password: '' });
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);

  const handleChange = (e) => {
    setFormData((prev) => ({
      ...prev,
      [e.target.name]: e.target.value,
    }));
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    setError(null);

    if (!formData.email || !formData.password) {
      setError('Please fill all fields');
      return;
    }

    try {
      setIsLoading(true);
      await login(formData.email, formData.password);
      setFormData({ email: '', password: '' });
      navigate('/dashboard');
    } catch (err) {
      setError(err.message);
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        name="email"
        type="email"
        value={formData.email}
        onChange={handleChange}
        disabled={isLoading}
      />
      <input
        name="password"
        type="password"
        value={formData.password}
        onChange={handleChange}
        disabled={isLoading}
      />
      <button type="submit" disabled={isLoading}>
        {isLoading ? 'Loading...' : 'Login'}
      </button>
      {error && <div className="error">{error}</div>}
    </form>
  );
}

Второй подход яснее: состояние управляет UI.

Выводы

  • Декларативность — основа React и modern frontend
  • Описываешь ЧТО, а не КАК
  • Меньше ошибок — React отслеживает зависимости
  • Код читабельнее — ясна логика и состояния
  • Легче тестировать — чистые функции, предсказуемые результаты

Овладение декларативным стилем — это переход от junior разработчика к профессионалу!

Что такое декларативность? | PrepBro