React.js. Что такое рендер-пропсы

11.09.2021

Теги: FrontendJavaScriptReact.jsWeb-разработкаКомпонентТеорияФункция

Что такое render props

На концептуальном уровне понять render props очень просто. Давайте забудем на минуту о React и посмотрим на вещи в контексте ванильного JavaScript. У нас есть функция, которая вычисляет сумму двух чисел. Для начала мы просто хотим вывести результат вычисления в консоль.

const sum = (a, b) => {
    const result = a + b;
    console.log(result);
}

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

const sum = (a, b, fn) => {
    const result = a + b;
    fn(result);
}

const alertFn = (result) => {
    alert(result);
}

const debugFn = (result) => {
    console.log(result);
}

Мы передаем функции sum в качестве аргумента fn функцию обратного вызова. Затем функция sum вычисляет результат и вызывает функцию fn с этим результатом в качестве аргумента. Таким способом функция обратного вызова получает результат и может делать с ним всё, что угодно.

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

Допустим, у нас есть блог, на главной странице, как это обычно бывает, показывается список постов. И есть панель управления, где тоже показывается список постов, но с элементами управления. Посты мы получаем, обращаясь к серверу — и делаем это как в публичной части, так и в панели управления. Функционал получения списка постов от сервера есть смысл вынести в отдельный компонент DataProvider. Но этот компонент не будет рендерить список постов, а вместо этого у него будет рендер-проп с функцией, которая и будет показывать список.

<DataProvider render={data => admin ? <PostListForAdmin posts={data} /> : <PostListForUser posts={data} />} />

Начнем с создания компонента Blog, где и происходит вся магия рендер-пропсов:

import { useState } from 'react';
import DataProvider from './DataProvider';
import PostListForUser from './PostListForUser';
import PostListForAdmin from './PostListForAdmin';

export default function Blog() {
    const [admin, setAdmin] = useState(false);

    const toggle = () => setAdmin(!admin);

    const render = (data) => {
        return admin ? <PostListForAdmin posts={data} /> : <PostListForUser posts={data} />
    }

    return (
        <>
            <DataProvider render={render} />
            <button onClick={toggle}>Переключить на {admin ? 'user' : 'admin'}</button>
        </>
    )
}

Компонент DataProvider получает данные с сервера и сохраняет их в состоянии:

import { useEffect, useState } from 'react';

const url = 'https://jsonplaceholder.typicode.com/posts';

export default function DataProvider(props) {
    const [data, setData] = useState([]);

    useEffect(() => {
        fetch(url)
            .then(response => response.json())
            .then(json => setData(json.splice(0, 3)));
    }, []);

    return props.render(data);
}

Компоненты PostListForUser и PostListForAdmin отвечают за показ списка постов для обычного пользователя и для администратора блога:

export default function PostListForAdmin(props) {
    return (
        <div>
            {props.posts.length ? (
                props.posts.map(post => 
                    <div key={post.id}>
                        <h4>{post.title}</h4>
                        <p>{post.body}</p>
                    </div>
                )
            ) : (
                <p>No posts</p>
            )}
        </div>
    )
}
export default function PostListForAdmin(props) {
    return (
        <div>
            {props.posts.length ? (
                props.posts.map(post => 
                    <div key={post.id}>
                        <h4>{post.title}</h4>
                        <p>{post.body}</p>
                        <button>Редактировать</button>
                        <button>Удалить</button>
                    </div>
                )
            ) : (
                <p>No posts</p>
            )}
        </div>
    )
}

Поиск: JavaScript • React.js • Web-разработка • Frontend • Компонент • Теория • Функция • render

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.