React.js. Что такое рендер-пропсы
11.09.2021
Теги: Frontend • JavaScript • React.js • Web-разработка • Компонент • Теория • Функция
Что такое 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