2021. 1. 8. 16:04ㆍReact/React
1. Input 상태 관리
import React, { Component } from 'react';
import PhoneForm from './components/PhoneForm';
class App extends Component {
render() {
return (
<div>
<PhoneForm />
</div>
);
}
}
export default App;
import React, { Component } from 'react';
class PhoneForm extends Component {
state = {
name: '',
phone: ''
}
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value
});
}
render() {
return (
<form>
<input name="name" placeholder="이름" onChange={this.handleChange} value={this.state.name}/>
<input name="phone" placeholder="전화번호" onChange={this.handleChange} value={this.state.phone}/>
<div>
{this.state.name} {this.state.phone}
</div>
</form>
);
}
}
export default PhoneForm;
2. 배열 데이터
1) 배열 데이터 삽입
import React, { Component } from 'react';
import PhoneForm from './components/PhoneForm';
class App extends Component {
id = 0; // 고유 키 값
state = {
information: [],
}
handleCreate = (data) => {
const { information } = this.state;
this.setState({
information: information.concat({
...data,
id: this.id++
})
});
}
render() {
return (
<div>
<PhoneForm onCreate={this.handleCreate}/>
{JSON.stringify(this.state.information)}
</div>
);
}
}
export default App;
handleCreate 함수의 경우 다른 방식으로 배열에 저장할 수 있다. Object.assign의 파라미터의 경우, 빈 공간('{ }')에 data와 id 배열을 넣는다는 의미로 생각하면 쉽게 이해할 수 있다. 또한 id의 값은 렌더링하는 값이 아니기에 state에 넣지 않아도 된다.
...
handleCreate = (data) => {
const { information } = this.state;
this.setState({
information: information.concat(Object.assign({}, data, {
id: this.id++
}))
})
}
...
import React, { Component } from 'react';
class PhoneForm extends Component {
state = {
name: '',
phone: ''
}
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value
});
}
handleSubmit = (e) => { // 등록 버튼이 눌릴 때 마다 페이지가 리로딩하지 않도록 설정
e.preventDefault();
this.props.onCreate(this.state);
this.setState({
name: '',
phone: ''
})
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input name="name" placeholder="이름" onChange={this.handleChange} value={this.state.name}/>
<input name="phone" placeholder="전화번호" onChange={this.handleChange} value={this.state.phone}/>
<button type="submit">등록</button>
</form>
);
}
}
export default PhoneForm;
2) 배열 데이터 렌더링
map은 배열을 특정함수를 사용해서 전체적으로 변환해주고 싶을 때 사용한다. 기본적인 map 사용법 예시는 다음과 같다.
const numbers = [1,2,3,4,5];
const squared = numbers.map(n => n * n);
squared
map을 프로젝트에 적용한다면 다음과 같다.
import React, { Component } from 'react';
class PhoneInfo extends Component {
render() {
const { name, phone, id} = this.props.info;
const style = {
border: '1px solid black',
padding: '8px',
margin: '8px',
}
return (
<div style={style}>
<div><b>{name}</b></div>
<div><b>{phone}</b></div>
</div>
);
}
}
export default PhoneInfo;
import React, { Component } from 'react';
import PhoneInfo from './PhoneInfo';
class PhoneInfoList extends Component {
static defaultProps = {
data: []
}
render() {
const { data } = this.props;
const list = data.map(
info => (<PhoneInfo info={info} key={info.id} />)
)
return (
<div>
{list}
</div>
);
}
}
export default PhoneInfoList;
※ key 값은 내부적으로 제거하거나 업데이트하거나 추가할 때 그 작업을 효율적으로 하기위해 사용되는 값이다.
import React, { Component } from 'react';
class PhoneForm extends Component {
state = {
name: '',
phone: ''
}
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value
});
}
handleSubmit = (e) => { // 등록 버튼이 눌릴 때 마다 페이지가 리로딩하지 않도록 설정
e.preventDefault();
this.props.onCreate(this.state);
this.setState({
name: '',
phone: ''
})
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input name="name" placeholder="이름" onChange={this.handleChange} value={this.state.name}/>
<input name="phone" placeholder="전화번호" onChange={this.handleChange} value={this.state.phone}/>
<button type="submit">등록</button>
</form>
);
}
}
export default PhoneForm;
import React, { Component } from 'react';
import PhoneForm from './components/PhoneForm';
import PhoneInfoList from './components/PhoneInfoList';
class App extends Component {
id = 0; // 고유 키 값
state = {
information: [],
}
handleCreate = (data) => {
const { information } = this.state;
this.setState({
information: information.concat({
...data,
id: this.id++
})
});
}
render() {
return (
<div>
<PhoneForm onCreate={this.handleCreate}/>
<PhoneInfoList data={this.state.information}/>
</div>
);
}
}
export default App;
4) 배열 데이터 삭제
Javascript 내부 함수(.slice, .filter) 를 이용하여 삭제를 할 수 있다. 기본적인 사용법은 다음과 같다.
const numbers = [1,2,3,4,5];
numbers.slice(0,2); // 인덱스 0 ~ 2 전까지
numbers.slice(0,3); // 인덱스 0 ~ 3 전까지
numbers.slice(0,2).concat(numbers.slice(3,5) // 1,2,4,5
[
...numbers.slice(0,2),
10,
...numbers.slice(3.5)
]
numbers.filter(n => n > 3);
numbers.filter(n => n !== 3);
프로젝트에 적용한다면 다음과 같다.
import React, { Component } from 'react';
class PhoneInfo extends Component {
handleRemove = () => {
const { info, onRemove } = this.props;
onRemove(info.id);
}
render() {
const { name, phone } = this.props.info;
const style = {
border: '1px solid black',
padding: '8px',
margin: '8px',
}
return (
<div style={style}>
<div><b>{name}</b></div>
<div><b>{phone}</b></div>
<button onClick={this.handleRemove}>삭제</button>
</div>
);
}
}
export default PhoneInfo;
import React, { Component } from 'react';
import PhoneInfo from './PhoneInfo';
class PhoneInfoList extends Component {
static defaultProps = {
data: []
}
render() {
const { data, onRemove } = this.props;
const list = data.map(
info => (<PhoneInfo onRemove={onRemove} info={info} key={info.id} />)
)
return (
<div>
{list}
</div>
);
}
}
export default PhoneInfoList;
import React, { Component } from 'react';
import PhoneForm from './components/PhoneForm';
import PhoneInfoList from './components/PhoneInfoList';
class App extends Component {
id = 0; // 고유 키 값
state = {
information: [],
}
handleCreate = (data) => {
const { information } = this.state;
this.setState({
information: information.concat({
...data,
id: this.id++
})
});
}
handleRemove = (id) => {
const { information } = this.state; // 비구조화 할당
this.setState({
information: information.filter(info => info.id !== id)
});
}
render() {
return (
<div>
<PhoneForm onCreate={this.handleCreate}/>
<PhoneInfoList data={this.state.information} onRemove={this.handleRemove}/>
</div>
);
}
}
export default App;
5) 배열 데이터 수정
import React, { Component, Fragment } from 'react';
class PhoneInfo extends Component {
state = {
editing: false,
name: '',
phone: ''
}
handleRemove = () => {
const { info, onRemove } = this.props;
onRemove(info.id);
};
handleToggleEdit = () => {
const { info, onUpdate } = this.props;
if(this.state.editing) {
onUpdate(info.id, {
name: this.state.name,
phone: this.state.phone
});
} else {
this.setState({
name: info.name,
phone: info.phone
})
}
this.setState({
editing: !this.state.editing,
});
};
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value
});
}
render() {
const { name, phone } = this.props.info;
const { editing } = this.state;
const style = {
border: '1px solid black',
padding: '8px',
margin: '8px',
};
return (
<div style={style}>
{
editing ? (
<Fragment>
<div><input name="name" onChange={this.handleChange} value={this.state.name}/></div>
<div><input name="phone" onChange={this.handleChange} value={this.state.phone}/></div>
</Fragment>
) : (
<Fragment>
<div><b>{name}</b></div>
<div><b>{phone}</b></div>
</Fragment>
)
}
<button onClick={this.handleRemove}>삭제</button>
<button onClick={this.handleToggleEdit}>
{ editing ? '적용' : '수정' }
</button>
</div>
);
}
}
export default PhoneInfo;
import React, { Component } from 'react';
import PhoneInfo from './PhoneInfo';
class PhoneInfoList extends Component {
static defaultProps = {
data: []
}
render() {
const { data, onRemove, onUpdate } = this.props;
const list = data.map(
info => (<PhoneInfo onUpdate={onUpdate} onRemove={onRemove} info={info} key={info.id} />)
)
return (
<div>
{list}
</div>
);
}
}
export default PhoneInfoList;
import React, { Component } from 'react';
import PhoneForm from './components/PhoneForm';
import PhoneInfoList from './components/PhoneInfoList';
class App extends Component {
id = 0; // 고유 키 값
state = {
information: [],
}
handleCreate = (data) => {
const { information } = this.state;
this.setState({
information: information.concat({
...data,
id: this.id++
})
});
}
handleRemove = (id) => {
const { information } = this.state; // 비구조화 할당
this.setState({
information: information.filter(info => info.id !== id)
});
}
handleUpdate = (id, data) => {
const { information } = this.state;
this.setState({
information: information.map(
info => {
if(info.id === id) {
return {
id,
...data,
};
}
return info;
}
)
})
}
render() {
return (
<div>
<PhoneForm onCreate={this.handleCreate}/>
<PhoneInfoList data={this.state.information} onUpdate={this.handleUpdate} nRemove={this.handleRemove}/>
</div>
);
}
}
export default App;
6) 성능 최적화
import React, { Component, Fragment } from 'react';
class PhoneInfo extends Component {
...
shouldComponentUpdate(nextProps, nextState) {
if(this.state !== nextState) {
return true;
}
return this.props.info !== nextProps.info;
}
...
7) 이름 검색
import React, { Component } from 'react';
import PhoneForm from './components/PhoneForm';
import PhoneInfoList from './components/PhoneInfoList';
class App extends Component {
id = 3; // 고유 키 값
state = {
information: [
{
id: 0,
name: '홍길동',
phone: '010-0000-0001'
},
{
id: 1,
name: '고길동',
phone: '010-0000-0002'
},
{
id: 2,
name: '테스트',
phone: '010-0000-0003'
}
],
keyword: '',
}
handleChange = (e) => {
this.setState({
keyword: e.target.value
})
}
handleCreate = (data) => {
const { information } = this.state;
this.setState({
information: information.concat({
...data,
id: this.id++
})
});
}
handleRemove = (id) => {
const { information } = this.state; // 비구조화 할당
this.setState({
information: information.filter(info => info.id !== id)
});
}
handleUpdate = (id, data) => {
const { information } = this.state;
this.setState({
information: information.map(
info => {
if(info.id === id) {
return {
id,
...data,
};
}
return info;
}
)
})
}
render() {
return (
<div>
<PhoneForm onCreate={this.handleCreate}/>
<input placeholder="검색" onChange={this.handleChange} value={this.state.keyword} />
<PhoneInfoList data={this.state.information.filter(
info => info.name.indexOf(this.state.keyword) > -1
)}
onUpdate={this.handleUpdate} nRemove={this.handleRemove}/>
</div>
);
}
}
export default App;
8) DOM 직접 접근 (Ref)
focus, 특정 DOM의 크기, 스크롤 설정, 외부 라이브러리(차트) 등 직접적으로 DOM에 접근할 때 사용한다.
import React, { Component } from 'react';
class PhoneForm extends Component {
input = React.createRef();
state = {
name: '',
phone: ''
}
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value
});
}
handleSubmit = (e) => { // 등록 버튼이 눌릴 때 마다 페이지가 리로딩하지 않도록 설정
e.preventDefault();
this.props.onCreate(this.state);
this.setState({
name: '',
phone: ''
})
this.input.current.focus();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input name="name" placeholder="이름" onChange={this.handleChange} value={this.state.name} ref={this.input}/>
<input name="phone" placeholder="전화번호" onChange={this.handleChange} value={this.state.phone}/>
<button type="submit">등록</button>
</form>
);
}
}
export default PhoneForm;
3. 추가 참고
Redux, React Router, TDD, Design Pattern
[참고] velopert.com/reactjs-tutorials
[참고] www.facebook.com/velopert/
[참고] tech.madup.com/atomic-design/
[참고] delivan.dev/react/programming-patterns-with-react-hooks-kr/
[참고] kyounghwan01.github.io/blog/React/container-presenter-dessign-pattern/
'React > React' 카테고리의 다른 글
[React] React 작업 환경 설정 (0) | 2021.01.08 |
---|---|
[React] LifeCycle API (0) | 2021.01.08 |
[React] Props, State (0) | 2021.01.08 |
[React] JSX 기본 문법, 스타일 (0) | 2021.01.08 |