React 에서 <h1>Hello World!</h1> 을 injecting 하려면
import React from 'react'
import ReactDOM from 'react-dom'
ReactDOM.render(<h1>Hello World!</h1>, document.getElementById('app'))
ReactDOM.render(
React.DOM.h1(null, 'Hello World!'),
document.getElementById('app')
)
커스텀 컴포넌트
// hooks 방식
const BlogPostExcerpt = () => {
return (
<div>
<h1>Title</h1>
<p>Description</p>
</div>
)
}
// class 방식
import React, { Component } from 'react'
class BlogPostExcerpt extends Component {
render() {
return (
<div>
<h1>Title</h1>
<p>Description</p>
</div>
)
}
}
State
constructor 에서 기본값을 설정합니다
class BlogPostExcerpt extends Component {
constructor(props) {
super(props)
this.state = { clicked: false }
}
render() {
return (
<div>
<h1>Title</h1>
<p>Description</p>
<p>Clicked: {this.state.clicked}</p>
</div>
)
}
}
상태 변경
// 이렇게 사용하면 안됩니다
this.state.clicked = true
이렇게 사용하면 안됩니다.
반드시 setState 를 사용해야 합니다
this.setState({ clicked: true })
setState 를 사용해야 하는 이유
React 가 state 의 변경을 알고 있어야 하고 React 가 그런 변경을 모아서 실제 DOM 을 업데이트 해야 합니다
두개의 컴포넌트가 state 를 공유하는 경우
Unidirectional Data Flow 원칙 때문에 컴포넌트 간에 데이터 공유시에 데이터가 변경되어야 하는 경우는
상위 컴포넌트가 state 를 가지고 있어야 하고 state 에 대한 변경 이벤트도 상위 컴포넌트에 있어야 함
// 금액단위를 Display , CurrencySwitcher 컴포넌트가 같이 사용하고 있다
class Converter extends React.Component {
constructor(props) {
super(props)
this.state = { currency: '€' }
}
render() {
return (
<div>
<Display currency={this.state.currency} />
<CurrencySwitcher currency={this.state.currency} />
</div>
)
}
}
// CurrencySwitcher 컴포넌트가 통화를 변경하기 위해서
// handleChangeCurrency 를 만들어서 자식 컴포넌트에게 전달해준다
class Converter extends React.Component {
constructor(props) {
super(props)
this.state = { currency: '€' }
}
handleChangeCurrency = event => {
this.setState({ currency: this.state.currency === '€' ? '$' : '€' })
}
render() {
return (
<div>
<Display currency={this.state.currency} />
<CurrencySwitcher
currency={this.state.currency}
handleChangeCurrency={this.handleChangeCurrency}
/>
</div>
)
}
}
const CurrencySwitcher = props => {
return (
<button onClick={props.handleChangeCurrency}>
Current currency is {props.currency}. Change it!
</button>
)
}
const Display = props => {
return <p>Current currency is {props.currency}.</p>
}
Props
컴포넌트가 속성 데이터를 얻는 방법이다
class 컴포넌트에서는 this.props 로 접근할 수 있다
props 는 자식 컴포넌트로 데이터를 전달하는 좋은 방법이지만 아래같은 경우 복잡해진다
- 여러 수준 아래에 있는 자식 컴포넌트에서 state 를 사용해야 할 때 (중간에 있는 컴포넌트들이 전부 props 를 bypass 해줘야 함)
- 완전히 관련이 없는 컴포넌트가 다른 컴포넌트의 state 를 사용해야 할 때
// function components
const BlogPostExcerpt = props => {
return (
<div>
<h1>{props.title}</h1>
<p>{props.description}</p>
</div>
)
}
// class components
import React, { Component } from 'react'
class BlogPostExcerpt extends Component {
render() {
return (
<div>
<h1>{this.props.title}</h1>
<p>{this.props.description}</p>
</div>
)
}
}
Props 전달 방법
HTML 의 속성과 비슷한 방식으로 props 를 전달합니다
const desc = 'A description'
//...
<BlogPostExcerpt title="A blog post" description={desc} />
Children
<BlogPostExcerpt title="A blog post" description="{desc}">
Something
</BlogPostExcerpt>
Something 을 접근하려면 this.props.children 으로 접근해야 한다
Presentational vs container components
- Presentational Components : UI 중심
- Container Components : 데이터 처리 중심
// presentational component
const Users = props => (
<ul>
{props.users.map(user => (
<li>{user}</li>
))}
</ul>
)
// container component
class UsersContainer extends React.Component {
constructor() {
this.state = {
users: []
}
}
componentDidMount() {
axios.get('/users').then(users =>
this.setState({ users: users }))
)
}
render() {
return <Users users={this.state.users} />
}
}
State vs props
- state : 컴포넌트가 직접 관리 하는 변수
- props : 부모 컴포넌트로 부터 받은 변수
PropTypes
props 의 type 을 강제해서 잘 못 된 값들이 넘어오는 것을 사전에 방지 할 수 있다
import PropTypes from 'prop-types'
import React from 'react'
class BlogPostExcerpt extends Component {
render() {
return (
<div>
<h1>{this.props.title}</h1>
<p>{this.props.description}</p>
</div>
)
}
}
BlogPostExcerpt.propTypes = {
title: PropTypes.string,
description: PropTypes.string
}
export default BlogPostExcerpt
- PropTypes.array
- PropTypes.bool
- PropTypes.func
- PropTypes.number
- PropTypes.object
- PropTypes.string
- PropTypes.symbol
// 둘 중 하나 허용
PropTypes.oneOfType([
PropTypes.string,
PropTypes.number
]),
// 여러 유형 허용
PropTypes.oneOf(['Test1', 'Test2']),
// 클래스의 인스턴스 허용
PropTypes.instanceOf(Something)
// React 의 node 허용
PropTypes.node
// 모든 타입 허용
PropTypes.any
// 배열도 적용가능
PropTypes.arrayOf(PropTypes.string)
// 오브젝트도 가능
PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
})
// 속성 누락시에 오류를 내도록 필수로 설정 가능
PropTypes.arrayOf(PropTypes.string).isRequired,
PropTypes.string.isRequired,
React Fragment
컴포넌트는 1개의 element 를 return 해야 합니다.
return 시에 최상위 태그를 React.Fragment 또는 <></> 를 사용합니다
import React, { Component } from 'react'
class BlogPostExcerpt extends Component {
render() {
return (
<>
<h1>{this.props.title}</h1>
<p>{this.props.description}</p>
</>
)
}
}
이벤트 처리
camelCase 를 사용하여 이벤트를 처리 합니다
const CurrencySwitcher = props => {
return (
<button onClick={props.handleChangeCurrency}>
Current currency is {props.currency}. Change it!
</button>
)
}
이벤트 핸들러를 컴포넌트 함수로 정의하는 것이 일반적입니다
class Converter extends React.Component {
handleChangeCurrency = event => {
this.setState({ currency: this.state.currency === '€' ? '$' : '€' })
}
}
클래스 컴포넌트를 사용시에는 this 를 바인딩 하세요
class Converter extends React.Component {
handleClick = e => {
/* ... */
}
//...
}
// 아니면 constructor 에서 this 를 바인딩 해줘야 함
class Converter extends React.Component {
constructor(props) {
super(props)
this.handleClick = this.handleClick.bind(this)
}
handleClick(e) {}
}
사용가능한 이벤트 리스트
Clipboard
- onCopy
- onCut
- onPaste
Composition
- onCompositionEnd
- onCompositionStart
- onCompositionUpdate
Keyboard
- onKeyDown
- onKeyPress
- onKeyUp
Focus
- onFocus
- onBlur
Form
- onChange
- onInput
- onSubmit
Mouse
- onClick
- onContextMenu
- onDoubleClick
- onDrag
- onDragEnd
- onDragEnter
- onDragExit
- onDragLeave
- onDragOver
- onDragStart
- onDrop
- onMouseDown
- onMouseEnter
- onMouseLeave
- onMouseMove
- onMouseOut
- onMouseOver
- onMouseUp
Selection
- onSelect
Touch
- onTouchCancel
- onTouchEnd
- onTouchMove
- onTouchStart
UI
- onScroll
Mouse Wheel
- onWheel
Media
- onAbort
- onCanPlay
- onCanPlayThrough
- onDurationChange
- onEmptied
- onEncrypted
- onEnded
- onError
- onLoadedData
- onLoadedMetadata
- onLoadStart
- onPause
- onPlay
- onPlaying
- onProgress
- onRateChange
- onSeeked
- onSeeking
- onStalled
- onSuspend
- onTimeUpdate
- onVolumeChange
- onWaiting
Image
- onLoad
- onError
Animation
- onAnimationStart
- onAnimationEnd
- onAnimationIteration
Transition
- onTransitionEnd
이벤트의 생성주기
- Mounting
- Constructor : 컴포넌트를 마운팅 할 때 첫번째로 호출
- getDerivedStateFromProps() :
- render()
- componentDidMount() : API 호출을 수행하거나 DOM 에서 작업을 처리할 때 사용합니다
- Updating
- getDerivedStateFromProps()
- shouldComponentUpdate()
- render()
- getSnapshotBeforeUpdate()
- componentDidUpdate() : 컴포넌트가 DOM 에서 업데이트 되었을 때 호출 합니다
- Unmounting
- componentWillUnmount() : 컴포넌트가 DOM 에서 제거될 때 호출
React 에서 Forms 사용방법
React 에서 Form 을 이용하여 데이터를 처리 하는 두가지 방법( DOM 이 data 를 핸들링 하는 경우와 컴포넌트가 data 를 핸들링 하는 경우 ) 이 있습니다
uncontrolled components vs controlled components
- controlled components : data 를 컴포넌트가 핸들링
- uncontrolled components : data 를 DOM 이 핸들링 (input elements 에서 states 를 사용하지 않는다)
- input type : file, date
controlled components 의 예
value 와 onChange 를 이용해서 state 정보를 관리 합니다
handleChange 에서 이전값과 현재값을 확인할 수 있기에 여기서 validation 체크를 해줍니다
class Form extends React.Component {
constructor(props) {
super(props)
this.state = { username: '' }
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleChange(event) {
this.setState({ value: event.target.value })
}
handleSubmit(event) {
alert(this.state.username)
event.preventDefault()
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input
type="text"
value={this.state.username}
onChange={this.handleChange}
/>
<input type="submit" value="Submit" />
</form>
)
}
}
textarea 의 예제
<textarea value={this.state.address} onChange={this.handleChange} />
select 의 예제
<select value="{this.state.age}" onChange="{this.handleChange}">
<option value="teen">Less than 18</option>
<option value="adult">18+</option>
</select>
uncontrolled components 의 예
file, date 같은 경우는 React.createRef() 를 이용해서 필드에 대한 참조를 생성해서 사용해야 합니다
constructor 에서 참조를 생성하고 binding 하고
input file 에 생성한 참조를 연결하고
onSubmit 에서 binding Submit 을 연결하고
handleSubmit 에서 참조를 이용하여 file 을 확인해서 처리해준다
class FileInput extends React.Component {
constructor(props) {
super(props)
this.curriculum = React.createRef()
this.handleSubmit = this.handleSubmit.bind(this)
}
handleSubmit(event) {
alert(this.curriculum.current.files[0].name)
event.preventDefault()
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input type="file" ref={this.curriculum} />
<input type="submit" value="Submit" />
</form>
)
}
}
아래 date 의 경우도
constructor 에서 inputRef 참조를 생성하고
input date 에 생성한 inputRef 를 연결
onSubmit 에 직접 함수를 생성하여 처리해줬다
(binding 함수를 만들어서 연결하지는 않고 직접 함수를 작성)
import React, { Component } from "react";
class UncontrolledComponent extends Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
render() {
return (
<form
onSubmit={(event) => {
event.preventDefault();
console.log("Input value - ", this.inputRef.current.value);
}}
>
<div>
<label>Uncontrolled input </label>
<input type="date" name="data" id="date-input" ref={this.inputRef} />
</div>
<button type="submit">Submit</button>
</form>
);
}
}
export default UncontrolledComponent;
state 를 DOM 에서 직접 저장되고 처리됩니다 (컴포넌트에서 처리 하지 않음)
이런 번거로운 Form 처리 방식을 개선하는 라이브러리로 formik 이 있습니다 https://formik.org/
DOM element 의 참조 만드는 방법
DOM 을 직접 건드리는 것보다 참조를 만들어서 액세스 하는 것이 좋다고 합니다
참조를 만드는 방법
ref={el => this.someProperty = el}
class SomeComponent extends Component {
render() {
return <button ref={el => (this.button = el)} />
}
}
'IT > React' 카테고리의 다른 글
React Native 벡터 아이콘 사용하기 vetor-icon (0) | 2022.08.05 |
---|---|
React 18 에는 enzyme 사용하지 마세요 (0) | 2022.08.01 |
REACT NATIVE UI COMPONENT (0) | 2022.08.01 |
Context API React (0) | 2022.08.01 |
React JSX (0) | 2022.07.27 |
React 기본개념 (0) | 2022.07.27 |
React 를 위한 자바스크립트 컨셉 이해하기 (0) | 2022.07.27 |
React 개발 환경 설정 (0) | 2022.07.26 |