프로젝트 생성, 코드 준비
우선, create-react-app 을 통하여 리액트 프로젝트를 생성하세요.
$ npx create-react-app react-test-tutorial
이미 알고 계실 수도 있겠지만, CRA 로 만든 리액트 프로젝트에는 테스트 환경이 이미 다 준비가 되어있고, 기본 테스트 파일 (App.test.js) 또한 존재 하지요.
한번 해당 파일을 확인해볼까요?
src/App.test.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
ReactDOM.unmountComponentAtNode(div);
});
해당 컴포넌트가, 크래쉬 없이 제대로 렌더링이 되었는지 확인을 해줍니다. 이걸 실행하려면, 터미널로 프로젝트의 디렉토리에서 yarn test 를 입력하시면 됩니다.
그러면, 다음과 같은 결과가 나타납니다:
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.672s, estimated 1s
Ran all test suites related to changed files.
Watch Usage
› Press p to filter by a filename regex pattern.
› Press t to filter by a test name regex pattern.
› Press q to quit watch mode.
› Press Enter to trigger a test run.
다 잘 됐다고 나타나지요.
자, 이제 우리는 아주 간단한 리액트 컴포넌트 3가지를 만들어보도록 하겠습니다.
카운터 만들기
단순히 state 에 있는 값을 + 버튼과 - 버튼을 통하여 변경하는 Counter 컴포넌트 입니다.
src/components/Counter.js
import React, { Component } from 'react';
class Counter extends Component {
state = {
value: 1
}
onIncrease = () => {
this.setState(({value}) => ({ value: value + 1 }));
}
onDecrease = () => {
this.setState(({value}) => ({ value: value - 1 }));
}
render() {
const { value } = this.state;
const { onIncrease, onDecrease } = this;
return (
<div>
<h1>카운터</h1>
<h2>{value}</h2>
<button onClick={onIncrease}>+</button>
<button onClick={onDecrease}>-</button>
</div>
);
}
}
export default Counter;
그리고, 이 컴포넌트를 App 에서 렌더링하세요.
src/App.js
import React, { Component } from 'react';
import Counter from './components/Counter';
class App extends Component {
render() {
return (
<div>
<Counter />
</div>
);
}
}
export default App;
그리고, yarn start
를 하시면 다음과 같이 나타날 것입니다.
NameForm, NameList 구현하기
이번에는, 이름을 NameForm에 입력해서 등록하면 NameList 에 나타나도록 컴포넌트들을 구현하겠습니다. input 의 상태값은 NameForm 에 넣고, NameList 에서 보여줄 이름 목록에 대한 상태값은 App 에서 NameList 로 props 를 통하여 전달해주도록 설정하겠습니다.
src/components/NameForm.js
import React, { Component } from 'react';
class NameForm extends Component {
static defaultProps = {
onSubmit: () => console.warn('onSubmit not defined'),
}
state = {
name: ''
}
onChange = (e) => {
this.setState({
name: e.target.value
});
}
onSubmit = (e) => {
const { name } = this.state;
const { onInsert } = this.props;
// 이름을 추가하고, name 값 초기화
onInsert(name);
this.setState({
name: ''
});
e.preventDefault(); // submit 하면 기본적으로는 페이지가 새로고쳐지게 되는데 이를 방지함
}
render() {
const { onSubmit, onChange } = this;
const { name } = this.state;
return (
<form onSubmit={onSubmit}>
<label>이름</label>
<input type="text" value={name} onChange={onChange} />
<button type="submit">등록</button>
</form>
);
}
}
export default NameForm;
src/components/NameList.js
import React, { Component } from 'react';
class NameList extends Component {
static defaultProps = {
names: []
}
renderList() {
const { names } = this.props;
const nameList = names.map(
(name, i) => (<li key={i}>{name}</li>)
);
return nameList;
}
render() {
return (
<ul>
{ this.renderList() }
</ul>
);
}
}
export default NameList;
자, 이제 우리가 방금 만든 컴포넌트 두개를 App 에서 렌더링해주겠습니다. 이 과정에서 App 에서 state 값과 onInsert 메소드를 추가해줄게요.
src/App.js
import React, { Component } from 'react';
import Counter from './components/Counter';
import NameForm from './components/NameForm';
import NameList from './components/NameList';
class App extends Component {
state = {
names: ['벨로퍼트', '김민준']
}
onInsert = (name) => {
this.setState(({names}) => ({ names: names.concat(name) }));
}
render() {
const { names } = this.state;
const { onInsert } = this;
return (
<div>
<Counter />
<hr />
<h1>이름 목록</h1>
<NameForm onInsert={onInsert}/>
<NameList names={names}/>
</div>
);
}
}
export default App;
이러한 결과가 완성 됐나요? 일단 제대로 작동하는지 확인해보세요.