5 React 데이터 가져오기 패턴
Sooner or later you will need to fetch data from an API, let's have a look at how we can handle data in React!👌
이 튜토리얼에서는 React에서 가장 일반적인 데이터 가져오기 패턴을 다룰 것입니다.
Originally posted on Nordschool.
당신은 읽습니까? 해보자! 💪
개요
먼저 큰 그림을 본 다음 더 깊이 파고들어 봅시다.
우리가 다룰 패턴:
프로젝트 구조
다양한 데이터 가져오기 패턴을 보여주기 위해 작은 반응 프로젝트를 만들었습니다. 초기화된 프로젝트create-react-app에는 표준 구조가 있습니다. 👇
├── README.md
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
├── src
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── actions
│ │ ├── api.js
│ │ ├── index.js
│ │ └── types.js
│ ├── hooks
│ │ ├── UseDataApi.js
│ ├── components
│ │ ├── HOC.js
│ │ ├── Standalone.js
│ │ ├── PostsList.js
│ │ ├── RenderProps.js
│ │ ├── WithCustomMiddleware.js
│ │ ├── WithCustomHook.js
│ │ └── WithHooks.js
│ ├── index.css
│ ├── index.js
│ ├── middleware
│ │ └── api.js
│ ├── reducers
│ │ └── index.js
│ ├── serviceWorker.js
│ └── store
│ └── index.js
└── yarn.lock
우리는 구성 요소를 다룰 것입니다.
기본 루트 구성 요소는 다음과 같습니다.
// App.js
import React from 'react';
import './App.css';
import Standalone from './components/Standalone';
import HOC from './components/HOC';
import WithHooks from './components/WithHooks';
import WithCustomHook from './components/WithCustomHook';
import RenderProps from './components/RenderProps';
import WithCustomMiddleware from './components/WithCustomMiddleware';
import PostsList from './components/PostsList';
function App() {
return (
<div className="App">
<h3>Standalone</h3>
<Standalone />
<h3>HOC</h3>
<HOC />
<h3>WithHooks</h3>
<WithHooks />
<h3>With Custom Hook</h3>
<WithCustomHook />
<h3>Render Props</h3>
<RenderProps children={PostsList} />
<h3>With Custom Middleware</h3>
<WithCustomMiddleware />
</div>
);
}
export default App;
가장 간결한 패턴부터 시작하겠습니다...
독립형
이 독립 실행형 구성 요소는 데이터 가져오기 및 렌더링을 모두 처리합니다.
// components/Standalone.js
import React, { Component } from 'react';
import axios from 'axios';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';
// API END POINT
const POSTS_SERVICE_URL = 'https://jsonplaceholder.typicode.com/posts';
class Standalone extends Component {
state = {
// Initial state.
isFetching: false,
posts: []
};
render() {
return (
<Paper>
<Table aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>Id </TableCell>
<TableCell>Title</TableCell>
<TableCell>Body</TableCell>
</TableRow>
</TableHead>
<TableBody>
{this.state.posts.map(row => (
<TableRow key={row.id}>
<TableCell component="th" scope="row">
{row.id}
</TableCell>
<TableCell>{row.title}</TableCell>
<TableCell>{row.body}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
<p>{this.state.isFetching ? 'Fetching posts...' : ''}</p>
</Paper>
);
}
componentDidMount() {
this.fetchPosts();
}
async fetchPostsAsync() {
try {
this.setState({ ...this.state, isFetching: true }); // Sets loading state.
const response = await axios.get(POSTS_SERVICE_URL);
this.setState({
...this.state,
isFetching: false,
posts: response.data.slice(0, 5) // Take first 5 posts only
});
} catch (e) {
console.log(e);
this.setState({ ...this.state, isFetching: false });
}
}
fetchPosts = this.fetchPostsAsync;
}
export default Standalone;
데이터 가져오기에서 뷰를 분리할 수 있는지 봅시다 🤓...
HOC
HOC(Higher-Order Component) 패턴은 React에서 일반적입니다. 이와 같은 구성 요소는 컨테이너 구성 요소라고도 합니다.
아이디어는 간단합니다. 데이터 가져오기는 데이터 표시와 분리됩니다.
// HOC.js
import React, { Component } from 'react';
import Simple from './Simple';
import axios from 'axios';
const POSTS_SERVICE_URL = 'https://jsonplaceholder.typicode.com/posts';
class HOC extends Component {
state = {
isFetching: false,
posts: []
};
render = () => (
<Simple data={this.state.posts} isFetching={this.state.isFetching}></Simple>
);
componentDidMount() {
this.fetchPosts();
}
async fetchPostsAsync() {
try {
this.setState({ ...this.state, isFetching: true });
const response = await axios.get(POSTS_SERVICE_URL);
this.setState({
...this.state,
isFetching: false,
posts: response.data.slice(0, 5)
}); // Take first 5 posts only
} catch (e) {
console.log(e);
this.setState({ ...this.state, isFetching: false });
}
}
fetchPosts = this.fetchPostsAsync;
}
export default HOC;
프레젠테이션 구성 요소는 다음과 같습니다.
// PostsList.js
import React from 'react';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';
const PostsList = props => {
return (
<Paper>
<Table aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>Id </TableCell>
<TableCell>Title</TableCell>
<TableCell>Body</TableCell>
</TableRow>
</TableHead>
<TableBody>
{props.data.map(row => (
<TableRow key={row.id}>
<TableCell component="th" scope="row">
{row.id}
</TableCell>
<TableCell>{row.title}</TableCell>
<TableCell>{row.body}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
<p>{props.isFetching ? 'Fetching posts...' : ''}</p>
</Paper>
);
};
export default PostsList;
하지만 일을 처리하는 더 나은 방법이 있을 수 있다고 말하면 어떻게 될까요? 😁
이것이 Hooks에서 어떻게 작동하는지 살펴보겠습니다.
후크 포함
이 패턴은 HOC와 유사하지만 후크와 함께 기능적 구성 요소를 사용합니다.
// WithHooks.js
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import Simple from './Simple';
const POSTS_SERVICE_URL = 'https://jsonplaceholder.typicode.com/posts';
function WithHooks() {
const [data, setData] = useState({ posts: [], isFetching: false });
useEffect(() => {
const fetchUsers = async () => {
try {
setData({ ...data, isFetching: true });
const response = await axios.get(POSTS_SERVICE_URL);
setData({
...data,
posts: response.data.slice(0, 5),
isFetching: false
});
} catch (e) {
console.log(e);
setData({ ...data, isFetching: false });
}
};
fetchUsers();
}, []); // Runs once
return <Simple data={data.posts} isFetching={data.isFetching} />;
}
export default WithHooks;
한 단계 더 나아가 모든 API에서 데이터를 가져오는 일반 후크를 만들 수도 있습니다.
일반 데이터 가져오기 후크의 간단한 버전:
// hooks/UseDataApi.js
import { useEffect, useState } from 'react';
import axios from 'axios';
const useDataApi = url => {
// This is just for demo purposes, you probably want to separate the data from loading state and potentially add other states such as failures, etc..
const [dataState, setDataState] = useState({ data: [], isFetching: false });
const [endpointUrl] = useState(url);
useEffect(() => {
const fetchDataFromApi = async () => {
try {
setDataState({ ...dataState, isFetching: true });
const response = await axios.get(endpointUrl);
setDataState({
...dataState,
data: response.data,
isFetching: false
});
} catch (e) {
console.log(e);
setDataState({ ...dataState, isFetching: false });
}
};
fetchDataFromApi();
}, []); // Runs once
return [dataState];
};
export default useDataApi;
후크가 준비되면 다음과 같이 사용할 수 있습니다 ...
// components/WithCustomHook.js
import React from 'react';
import UseDataApi from '../hooks/UseDataApi';
import PostsList from './PostsList';
const POSTS_SERVICE_URL = 'https://jsonplaceholder.typicode.com/posts';
function WithHooks() {
const [dataState] = UseDataApi(POSTS_SERVICE_URL);
return (
<PostsList
data={dataState.data.slice(0, 5)}
isFetching={dataState.isFetching}
/>
);
}
export default WithHooks;
We recommend this pattern for most cases! This pattern is reusable and does separation of concern well.
좋아, 지금까지 너무 좋아.
그러나 동일한 데이터를 표시하는 많은 프레젠테이션 구성 요소가 있는 경우에는 어떻게 해야 합니까?
일반적으로 Hooks는 대부분의 논리 캡슐화 사례를 다룰 수 있습니다. 그러나 몇 가지limitations가 있을 수 있습니다.
렌더링 소품
이 사용 사례에 대해 렌더링 소품 대신 후크를 사용할 수 있지만 렌더링 소품은 또 다른 실행 가능한 옵션입니다.
렌더 소품은 다양한 프레젠테이션 구성 요소에 대해 재사용 가능한 래퍼 역할을 합니다.
// RenderProps.js
import { Component } from 'react';
import axios from 'axios';
const POSTS_SERVICE_URL = 'https://jsonplaceholder.typicode.com/posts';
class RenderProps extends Component {
state = {
isFetching: false,
data: []
};
render = () => this.props.children(this.state);
componentDidMount() {
this.fetchPosts();
}
async fetchPostsAsync() {
try {
this.setState({ ...this.state, isFetching: true });
const response = await axios.get(POSTS_SERVICE_URL);
this.setState({
...this.state,
isFetching: false,
data: response.data.slice(0, 5)
}); // Take first 5 posts only
} catch (e) {
console.log(e);
this.setState({ ...this.state, isFetching: false });
}
}
fetchPosts = this.fetchPostsAsync;
}
export default RenderProps;
이것이 Vanilla React 패턴의 전부입니다! 🙌
Redux는 어떻습니까? 어떻게 생겼을까요? 슬쩍 보여드리겠습니다.
Redux 커스텀 미들웨어
다음은 custom middleware 을 사용하는 간단한 예입니다.
// components/WithCustomMiddleware.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import PostsList from './PostsList';
import { fetchPosts } from '../actions';
class WithCustomMiddleware extends Component {
state = {};
componentDidMount() {
this.props.fetchPosts();
}
render = () => (
<PostsList
data={this.props.data}
isFetching={this.props.isFetching}
></PostsList>
);
}
const mapStateToProps = ({ data = [], isFetching = false }) => ({
data,
isFetching
});
export default connect(
mapStateToProps,
{ fetchPosts }
)(WithCustomMiddleware);
Redux 미들웨어가 어떻게 작동하는지 잘 모르시겠습니까? custom redux middleware 생성 방법에 대한 이 짧은 자습서를 확인하십시오.
이제 React에서 데이터 가져오기를 처리하는 방법을 알았습니다! ✋
지원하다
기사를 즐겼습니까? Twitter에서 요약 스레드를 공유합니다.
노드스쿨
@nordschool
👌- Standalone- HOC- With Hooks- Render Props- Redux Custom MiddlewareTHREAD... 👇에서 가장 일반적인 API 데이터 가져오기 패턴
오전 08:38 - 2019년 10월 23일
1
2
더 나은 코드 월요일 뉴스레터
내 뉴스레터를 좋아할 수도 있습니다. 아이디어는 매주 월요일 3개의 웹 개발 팁을 공유하는 것입니다.
저의 목표는 작문 실력을 향상시키고 최대한 많은 지식을 공유하는 것입니다. 지금까지 수백 명의 개발자가 구독했고 좋아하는 것 같습니다.
내가 어떤 종류의 물건을 공유하는지 감을 잡으려면 previous newsletter issues 및 subscribe 을 확인하십시오.
Reference
이 문제에 관하여(5 React 데이터 가져오기 패턴), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/nordschool/5-react-data-fetching-patterns-6ci텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)