Обзор свойств рендеринга в React

Обзор свойств рендеринга в React

От автора: рендеринг в React — это метод эффективного повторного использования кода. Согласно документации React, «компонент со свойством рендеринга принимает функцию, которая возвращает элемент React и вызывает ее вместо реализации собственной логики визуализации». Чтобы понять, что это значит, давайте рассмотрим шаблон свойства рендеринга, а затем применим его в нескольких простых примерах.

Шаблон свойства рендеринга

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

class BaseComponent extends Component { render() { return <Fragment>{this.props.render()}</Fragment>; }
}

Представьте себе, что наше App — подарочная коробка, где App само по себе — это бантик сверху. Если коробка является компонентом, который мы создаем, и мы его открываем, мы достаем из него свойства, состояния, функции и методы, необходимые для работы компонента после вызова render().

Функция рендеринга компонента обычно имеет весь JSX и другое, что формирует DOM для этого компонента. Вместо этого этот компонент содержит функцию рендеринга this.props.render(), которая отображает компонент, передаваемый через свойства.

Пример: создание счетчика

Давайте рассмотрим простой пример счетчика, который увеличивает и уменьшает значение в зависимости от нажатия кнопки. Мы начнем с создания компонента, который будет использоваться для обертывания исходного состояния, методов и рендера. Без ухищрений мы назовем его Wrapper:

class Wrapper extends Component { state = { count: 0 }; // Increase count increment = () => { const { count } = this.state; return this.setState({ count: count + 1 }); }; // Decrease count decrement = () => { const { count } = this.state; return this.setState({ count: count - 1 }); }; render() { const { count } = this.state; return ( <div> {this.props.render({ increment: this.increment, decrement: this.decrement, count: count })} </div> ); }
}

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

Если вы посмотрите на метод return(), то увидите, что мы используем его this.props.render(). Именно через эту функцию мы передаем методы и состояние из компонента Wrapper, так что компонент, который его оборачивает, будет использовать его. Чтобы использовать компонент для нашего компонента App, он будет выглядеть так:

class App extends React.Component { render() { return ( <Wrapper render={({ increment, decrement, count }) => ( <div> <div> <h3>Render Props Counter</h3> </div> <div> <p>{count}</p> <button onClick={() => increment()}>Increment</button> <button onClick={() => decrement()}>Decrement</button> </div> </div> )} /> ); }
}

Пример: создание списка данных

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

Что мы хотим от компонента-оболочки на этот раз? Мы хотим передать исходную ссылку на данные, которые нужно отобразить, а затем выполнить GET-запрос на получение данных. Когда данные получены, мы устанавливаем их как новое состояние компонента и отображаем.

class Wrapper extends React.Component { state = { isLoading: true, error: null, list: [] }; fetchData() { axios.get(this.props.link) .then((response) => { this.setState({ list: response.data, isLoading: false }); }) .catch(error => this.setState({ error, isLoading: false })); } componentDidMount() { this.setState({ isLoading: true }, this.fetchData); } render() { return this.props.render(this.state); }
}

Ссылка на данные будет передана в качестве свойства для компонента Wrapper. Когда мы получаем ответ от сервера, мы обновляем list, используя то, что возвращается с сервера. Запрос выполняется сервером после монтирования компонентов. Вот как используется Wrapper:

class App extends React.Component { render() { return ( <Wrapper link="https://jsonplaceholder.typicode.com/users" render={({ list, isLoading, error }) => ( <div> <h2>Random Users</h2> {error ? <p>{error.message}</p> : null} {isLoading ? ( <h2>Loading...</h2> ) : ( <ul>{list.map(user => <li key={user.id}>{user.name}</li>)}</ul> )} </div> )} /> ); }
}

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

Компонент App здесь является компонентом класса, так как он не управляет состоянием. Мы можем превратить его в функциональный компонент без состояния.

const App = () => { return ( <Wrapper link="https://jsonplaceholder.typicode.com/users" render={({ list, isLoading, error }) => ( <div> <h2>Random Users</h2> {error ? <p>{error.message}</p> : null} {isLoading ? ( <h2>Loading...</h2> ) : ( <ul>{list.map(user => <li key={user.id}>{user.name}</li>)}</ul> )} </div> )} /> );
}

В завершение!

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

Автор: Kingsley Silas

Источник: https://css-tricks.com/

Редакция: Команда webformyself.