https://www.robinwieruch.de/react-fetching-data
리액트 컴포넌트 Tree 중 한 곳에서 Third Party API를 사용한다고 가정하자.
고려해야 할 사항
1. 어떤 컴포넌트에서 이 Data가 필요한가
2. 어디에서 로딩 중이라는 표시를 보여주고 싶은가
3. 에러 메시지를 어디에서 보여주고 싶은가?
- componentDidMount()
render 함수를 최초로 실행한 후, 받아온 Data가 setState 함수로 변경이 되면, 다시 render 된다.
Fetch함수는 javascript의 promise를 사용하여 비동기 응답을 해결한다. (더 조사 필요)
import React, { Component } from 'react';
const API = 'https://hn.algolia.com/api/v1/search?query=';
const DEFAULT_QUERY = 'redux';
class App extends Component {
constructor(props) {
super(props);
this.state = {
hits: [],
};
}
componentDidMount() {
fetch(API + DEFAULT_QUERY)
.then(response => response.json())
.then(data => this.setState({ hits: data.hits }));
}
render() {
const { hits } = this.state;
return (
<ul>
{hits.map(hit =>
<li key={hit.objectID}>
<a href={hit.url}>{hit.title}</a>
</li>
)}
</ul>
);
}
}
}
export default App;
componentDidMount() 전에 이미 render()가 실행되었음에도 불구하고,
hits props가 empty array로 이미 정의되었기 때문에 null pointer 에러가 나지 않는다.
class App extends Component {
constructor(props) {
super(props);
this.state = {
hits: [],
isLoading: false,
error : null,
};
}
componentDidMount() {
this.setState({ isLoading: true });
fetch(API + DEFAULT_QUERY)
.then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error('Something went wrong ...');
}
})
.then(data => this.setState({ hits: data.hits, isLoading: false }))
.catch(error => this.setState({ error, isLoading: false }));
}
render() {
const { hits, isLoading, error } = this.state;
if (error) {
return <p>{error.message}</p>;
}
if (isLoading) {
return <p>Loading ...</p>;
}
return (
<ul>
{hits.map(hit =>
<li key={hit.objectID}>
<a href={hit.url}>{hit.title}</a>
</li>
)}
</ul>
);
}
}
export default App;
- Loading
isLoading State는 asynchronous request가 일어나고 있다는 것을 알려주기 위해 사용된다.
fetch 진행 바로 직전에 isLoading을 true로 바꾸고,
fetch가 다 일어난 후에 setState를 활용해서 isLoading을 false로 바꾼다.
그리고 render함수 내에서 isLoading이 true인 경우 Loading이라는 글자가 보이도록 한다.
(이거 너무 좋은 거 같아 - https://github.com/danilowoz/react-content-loader)
- Error
catch로 error를 잡으면 error를 state에 저장해주고, isLoading false로 바꾼다.
=> native fetch API는 404에러가 뜨면, catch 블록까지 가지 않음.
이를 해결하기 위해 response를 분석하여 ok가 아니라면 throw new Error('something went wrong')으로 catch 블록에 도달할 수 있도록 한다.
에러를 보여주고 싶다면, if (error) 이부분으로 error메시지를 보여준다.
error가 발생했을 때, axios는 자동으로 catch에 가기 때문에 error를 throw할 필요가 없다.
axios는 자동으로 json response를 준다.
import React, { Component } from 'react';
import axios from 'axios';
const API = 'https://hn.algolia.com/api/v1/search?query=';
const DEFAULT_QUERY = 'redux';
class App extends Component {
constructor(props) {
super(props);
this.state = {
hits: [],
isLoading: false,
error: null,
};
}
componentDidMount() {
this.setState({ isLoading: true });
axios.get(API + DEFAULT_QUERY)
.then(result => this.setState({
hits: result.data.hits,
isLoading: false
}))
.catch(error => this.setState({
error,
isLoading: false
}));
}
...
}
export default App;
이전까지는, React의 componentDidMount lifecycle method에서 api 를 이용해 data를 받았지만,
버튼을 눌렀을 때, data를 받아오도록 할 수 도 있다.
이때는 componentDidMount와 같이 lifecycle을 사용하지 않고, 사용자가 직접 함수를 정의해서 사용한다.
import React, { Component } from 'react';
import axios from 'axios';
const API = 'https://hn.algolia.com/api/v1/search?query=';
const DEFAULT_QUERY = 'redux';
class App extends Component {
constructor(props) {
super(props);
this.state = {
hits: [],
isLoading: false,
error: null,
};
}
getStories() {
this.setState({ isLoading: true });
axios.get(API + DEFAULT_QUERY)
.then(result => this.setState({
hits: result.data.hits,
isLoading: false
}))
.catch(error => this.setState({
error,
isLoading: false
}));
}
...
}
export default App;
react는 get method 밖에 없지만, axios를 사용한다면 get과 post를 사용할 수 있다.
> [extensive React testing tutorial] https://www.robinwieruch.de/react-testing-tutorial
create-react-app으로 aplication을 setting 했다면, Jest가 test runner, assertion library로 정해져 있다.
아니라면, Mocha나 Chai를 대신 사용할 수도 있다.
리액트 컴포넌트를 testing할 때, 이 분은 Enzyme를 종종 사용하곤 한다고 한다.
--- test 하는 부분은 차후에 읽도록 하자.
[React] Virtual-DOM, Reconciliation, fiber (0) | 2021.06.21 |
---|---|
[MongoDB] Model Relationships Between Documents (3) (0) | 2021.06.10 |
[MongoDB] Model Relationships Between Documents (2) (0) | 2021.06.10 |
[MongoDB] Model Relationships Between Documents (1) (0) | 2021.06.10 |
[React] Fetch data in React (2)💦 (0) | 2021.05.27 |
댓글 영역