JavaScript в фигурных скобках в JSX в React компонентах

год назад·3 мин. на чтение

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

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

Передача строк в кавычках

Когда нужно передать строковый атрибут в JSX, нужно заключить его в одинарные или двойные кавычки:
export default function Avatar() {
  return (
    <img
      className="avatar"
      src="http://example.com/userpic.jpg"
      alt="User Name"
    />
  );
}
Здесь "http://example.com/userpic.jpg" и "User Name" передаются как строки. Но что, если вы хотите динамически указать src или alt? Вы можете использовать JavaScript значение, заменив " и " на { и }:
export default function Avatar() {
  const avatar = 'http://example.com/userpic.jpg';
  const description = 'User Name';
  return <img className="avatar" src={avatar} alt={description} />;
}
Обратите внимание на разницу между className="avatar", который указывает имя CSS класса "avatar", и src={avatar}, который считывает значение переменной JavaScript с именем avatar. Это потому, что фигурные скобки позволяют вам работать с JavaScript прямо в разметке.

Использование фигурных скобок: JavaScript в разметке

JSX — это особый способ написания JavaScript. Это означает, что внутри него можно использовать JavaScript — с помощью фигурных скобок { }. В приведенном ниже примере сначала объявляется имя, name, а затем оно встраивается в фигурные скобки внутри <h1>:
export default function TodoList() {
  const name = 'User Name';

  return <h1>{name}'s To Do List</h1>;
}
Любое выражение JavaScript будет работать между фигурными скобками, включая вызовы функций, таких как formatDate():
const today = new Date();

function formatDate(date) {
  return new Intl.DateTimeFormat('en-US', { weekday: 'long' }).format(date);
}

export default function TodoList() {
  return <h1>To Do List for {formatDate(today)}</h1>;
}

Где использовать фигурные скобки

Вы можете использовать фигурные скобки только двумя способами внутри JSX:
  1. Как текст непосредственно внутри тега JSX: <h1>{name}'s To Do List</h1> работает, но <{tag}>To Do List</{tag}> работать не будет.
  2. Поскольку атрибуты следуют сразу после знака =: src={avatar} будут считывать переменную avatar, но src="{avatar}" передаст строку "{avatar}".

Использование двойных фигурных скобок: CSS и другие объекты в JSX

Помимо строк, чисел и других выражений JavaScript, вы даже можете передавать объекты в JSX. Объекты также обозначаются фигурными скобками, например { name: "User Name", itemsCount: 10 }. Следовательно, чтобы передать объект JS в JSX, вы должны заключить объект в другую пару фигурных скобок: person={{ name: "User Name", itemsCount: 10 }}. Вы можете увидеть это со встроенными стилями CSS в JSX. React не требует от вас использования встроенных стилей (классы CSS отлично подходят для большинства случаев). Но когда вам нужен встроенный стиль, нужно передать объект атрибуту стиля:
export default function TodoList() {
  return (
    <ul
      style={{
        backgroundColor: 'black',
        color: 'pink',
      }}
    >
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
    </ul>
  );
}
Встроенные (inline) стили записываются в camelCase. Например, HTML <ul style="background-color: black"> в компоненте будет записан как <ul style={{ backgroundColor: 'black' }}>.

Другие примеры JavaScript объектов в фигурных скобках

Вы можете переместить несколько выражений в один объект и ссылаться на них в JSX внутри фигурных скобок:
const person = {
  name: 'User Name',
  theme: {
    backgroundColor: 'black',
    color: 'pink',
  },
};

export default function TodoList() {
  return (
    <div style={person.theme}>
      <h1>{person.name}'s Todos</h1>
      <img
        className="avatar"
        src="https://example.com/userpic.jpg"
        alt="userpic"
      />
      <ul>
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
      </ul>
    </div>
  );
}
В этом примере объект JavaScript person содержит строку имени и объект темы:
const person = {
  name: 'User Name',
  theme: {
    backgroundColor: 'black',
    color: 'pink',
  },
};
Компонент может использовать эти значения из person следующим образом:
<div style={person.theme}>
  <h1>{person.name}'s Todos</h1>
JSX очень минималистичен как язык шаблонов, потому что он позволяет вам организовывать данные и логику с помощью JavaScript.

Резюме

Теперь вы знаете почти все о JSX:
  • Атрибуты JSX внутри кавычек передаются как строки.
  • Фигурные скобки позволяют добавить в разметку логику и JavaScript переменные.
  • Они работают внутри содержимого тега JSX или сразу после = в атрибутах.
  • {{ и }} не являются специальным синтаксисом: это объект JavaScript, спрятанный внутри фигурных скобок JSX.

Как вызвать метод дочернего компонента из родительского компонента с помощью useImperativeHandle

2 года назад·3 мин. на чтение

Быстрый старт с useImperativeHandle

В этой статье будет показано, как вызвать метод дочернего компонента с помощью ссылки. Чтобы решить эту проблему, мы будем использовать хуки useRef и useImperativeHandle.

Дочерний компонент

Начнем с простого дочернего компонента, в котором содержится кнопка. Нажатие на кнопку вызывает внутренний метод doSomething.
// Child.jsx

function Child(props, ref) {
  const doSomething = () => {
    console.log("do something");
  };
  return (
    <div>
      <h1>Child Component</h1>
      <button onClick={doSomething}>Run</button>
    </div>
  );
}

export default Child;

Родительский компонент

Далее рассмотрим родительский компонент. В нем используется дочерний компонент, описанный выше. Обратите внимание, что в родительском компоненте есть собственная кнопка сохранения.
// App.jsx

import Child from "./Child";

function App() {
  const save = () => {};
  return (
    <div>
      <Child />
      <button onClick={save}>Save</button>
    </div>
  );
}

export default App;

Хук useImperativeHandle

Теперь давайте сосредоточимся на нашей задаче. Мы хотим вызвать метод (doSomething) дочернего компонента при нажатии кнопки (Save) из родительского компонента. Чтобы вызвать метод из дочернего компонента, нам нужно сначала выставить его наружу. useImperativeHandle определяет значение объекта, которое предоставляется родительскому компоненту при использовании ref. Добавляя наш метод к этому объекту, мы делаем его доступным в родительских компонентах.
// Child.jsx

import { useImperativeHandle } from "react";

function Child(props, ref) {
  const doSomething = () => {
    console.log("do something");
  };

  useImperativeHandle(ref, () => ({ doSomething }));

  return (
    <div>
      <h1>Child Component</h1>
      <button onClick={doSomething}>Run</button>
    </div>
  );
}
export default Child;
useImperativeHandle следует использовать с forwardRef.
forwardRef позволяет родительскому компоненту передавать ссылки своим дочерним элементам. Чтобы прикрепить функции или поля к этой ссылке (к рефу), используется хук useImperativeHandle.
// Child.jsx

import { forwardRef, useImperativeHandle } from "react";

function Child(props, ref) {
  const doSomething = () => {
    console.log("do something");
  };

  useImperativeHandle(ref, () => ({ doSomething }));

  return (
    <div>
      <h1>Child Component</h1>
      <button onClick={doSomething}>Run</button>
    </div>
  );
}

export default forwardRef(Child); // Child обернут в forwardRef
На этом этапе мы можем создать ссылку в родительском компоненте с помощью хука useRef и передать ее дочернему компоненту. Получив эту ссылку, мы можем вызвать метод doSomething дочернего компонента.
// App.jsx

import { useRef } from "react";
import Child from "./Child";

function App() {
  const childRef = useRef(null);

  const save = () => {
    if (childRef.current) {
      childRef.current.doSomething();
    }
  };

  return (
    <div>
      <Child ref={childRef} />
      <button onClick={save}>Save</button>
    </div>
  );
}

export default App;

Добавим TypeScript

Далее посмотрим, какие изменения нужно сделать, чтобы вызвать тот же дочерний метод из родительского компонента при использовании TypeScript. Во-первых, нам нужно определить новый интерфейс, содержащий метод, который будет представлен.
export interface RefType {
  doSomething: () => void;
}
Затем новый тип (RefType) используется при получении ссылки в дочернем компоненте.
function Child(props: PropsType, ref: Ref<RefType>)
Ниже приведен полный код дочернего компонента.
// Child.jsx

import { forwardRef, useImperativeHandle, Ref } from "react";

export interface PropsType {}
export interface RefType {
  doSomething: () => void;
}

function Child(props: PropsType, ref: Ref<RefType>) {
  const doSomething = () => {
    console.log("do something");
  };
  useImperativeHandle(ref, () => ({ doSomething }));
  return (
    <div>
      <h1>Child Component</h1>
      <button onClick={doSomething}>Run</button>
    </div>
  );
}

export default forwardRef(Child);
В родительский компонент нам нужно импортировать этот RefType, содержащий все публичные дочерние методы, и использовать его при создании ref.
// App.jsx

import Child, { RefType } from "./Child";
//...
const childRef = useRef<RefType>(null);
Полный код родительского компонента.
import { useRef } from "react";
import Child, { RefType } from "./Child";

function App() {
  const childRef = useRef<RefType>(null);

  const save = () => {
    if (childRef.current) {
      childRef.current.doSomething();
    }
  };

  return (
    <div>
      <Child ref={childRef} />
      <button onClick={save}>Save</button>
    </div>
  );
}

export default App;