728x90
* 연습과제 1
import './App.css';
import React, { Component } from 'react';
import youtubeVideos from './youtubeVideos'
import Button from './Button'
class App extends Component {
state = {
index: 0
}
decreaseIndex = () => {
const nextIndex = this.state.index - 1
this.setState({index: (nextIndex < 0) ? youtubeVideos.length - 1 : nextIndex})
}
increaseIndex = () => {
const nextIndex = this.state.index + 1
this.setState({index: (nextIndex > youtubeVideos.length - 1) ? 0 : nextIndex})
}
render(){
const { index } = this.state
const { increaseIndex, decreaseIndex } = this
const path = youtubeVideos[index].src
const title = youtubeVideos[index].title
return (
<div className="App">
<div className="img-container">
<iframe width="560" height="315" src={path} title={title} frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div>
<div className="control-btns">
<Button handleClick={decreaseIndex}>Prev</Button>
<Button handleClick={increaseIndex}>Next</Button>
</div>
</div>
);
}
}
export default App;
* 연습과제 2
import './App.css';
import React, { Component } from 'react';
import Button from './Button'
import loginData from './loginData';
class App extends Component {
state = {
id: '',
password: '',
isLogin: false
}
handleChange = (e) => {
const { name, value } = e.target
// console.log(name, value)
this.setState({ [name]: value}) // 주석처리하면 사용자 입력이 되지 않음
}
login = (e) => {
e.preventDefault() // 새로고침 방지
const { id, password } = this.state
if(id === loginData.USER_ID && password === loginData.USER_PASSWORD){
this.setState({isLogin: true})
}else{
alert('you failed to login !')
}
}
render(){
const { id, password, isLogin } = this.state
const loginForm = (
<form>
<label>ID <input type="text" placeholder="TYPE YOUR ID ..." name="id" value={id} onChange={this.handleChange}></input></label><br/><br/>
<label>PASSWORD <input type="password" placeholder="TYPE YOUR PASSWORD ..." name="password" value={password} onChange={this.handleChange}></input></label>
<div className="login-btn"><Button handleClick={this.login}>Login</Button></div>
</form>
)
const homePage = (
<h1>HOME PAGE</h1>
)
return (
<div className="App">
{isLogin? homePage: loginForm}
</div>
);
}
}
export default App;
* 연습과제 3
import './App.css';
import React, { Component } from 'react';
import Button from './Button'
import loginData from './loginData';
import Modal from './Modal';
class App extends Component {
state = {
id: '',
password: '',
isLogin: false,
open: false
}
openModal = () => {
this.setState({ open: true })
}
closeModal = () => {
this.setState({ open: false })
}
handleChange = (e) => {
const { name, value } = e.target
// console.log(name, value)
this.setState({ [name]: value}) // 주석처리하면 사용자 입력이 되지 않음
}
login = (e) => {
e.preventDefault() // 새로고침 방지
const { id, password } = this.state
if(id === loginData.USER_ID && password === loginData.USER_PASSWORD){
this.setState({isLogin: true})
}else{
this.openModal()
}
}
render(){
const { id, password, isLogin, open } = this.state
const loginForm = (
<>
<form>
<label>ID <input type="text" placeholder="TYPE YOUR ID ..." name="id" value={id} onChange={this.handleChange}></input></label><br/><br/>
<label>PASSWORD <input type="password" placeholder="TYPE YOUR PASSWORD ..." name="password" value={password} onChange={this.handleChange}></input></label>
<div className="login-btn"><Button handleClick={this.login}>Login</Button></div>
</form>
<Modal open={open}>
<p>You failed to login !</p>
<Button handleClick={this.closeModal}>Close</Button>
</Modal>
</>
)
const homePage = (
<h1>HOME PAGE</h1>
)
return (
<div className="App">
{isLogin? homePage: loginForm}
</div>
);
}
}
export default App;
* 연습과제 4
import './App.css';
import React, { Component } from 'react';
import Button from './Button'
class App extends Component {
constructor(props){
super(props)
this.state = {
files: []
}
this.fileInput = React.createRef() // ref 생성하기
}
isValid = (type) => {
return type === 'image'
}
handleChange = (e) => {
const files = e.target.files
const uploadedFiles = []
for(let file of files){
if(this.isValid(file.type.split('/')[0])){
console.log(file.name)
const name = file.name
const imgSrc = URL.createObjectURL(file)
uploadedFiles.push({ name, imgSrc })
}else{
alert(`file [${file.name}] type is not valid !`)
}
}
this.setState({ files: [...uploadedFiles, ...this.state.files]})
}
openFileWindow = () => {
this.fileInput.current.click() // ref 사용하기
}
render(){
const { files } = this.state
return (
<div className="App">
{files.length !== 0 && files.map( (file, id) => {
return (
<div key={id}>
<h3>{file.name}</h3>
<img src={file.imgSrc} alt={file.name} width="70px" height="100px"></img>
</div>
)
})}
<input className="Upload" type="file" onChange={this.handleChange} ref={this.fileInput} accept="image/*" multiple></input>
<Button handleClick={this.openFileWindow}>Upload</Button>
</div>
);
}
}
export default App;
* 연습과제 5
import './App.css';
import React, { Component } from 'react';
import Button from './Button'
import Sidebar from './Sidebar'
class App extends Component {
state = {
toggle: false,
menus: [
{
icon: '♜',
title: 'HOME'
},
{
icon: '♞',
title: 'ABOUT'
},
{
icon: '☻',
title: 'SETTING'
},
{
icon: '♜',
title: 'HOME'
},
{
icon: '♞',
title: 'ABOUT'
},
{
icon: '☻',
title: 'SETTING'
}
]
}
toggleMenu = () => {
this.setState({toggle: !this.state.toggle})
}
hideSideBar = () => {
this.setState({ toggle: false })
}
render(){
const { toggle, menus } = this.state
return (
<div className="App">
<Button handleClick={this.toggleMenu}>Open sidebar</Button>
<Sidebar open={toggle}>
{menus.map( (menu, id) => {
return <div className="menu" key={id} onClick={this.hideSideBar}>{menu.icon} {menu.title} </div>
})}
</Sidebar>
</div>
);
}
}
export default App;
메뉴를 클릭할때 hideSideBar 함수를 실행하면서 toggle 상태를 false 로 변경해주면 된다.
* 연습과제 6
import './App.css';
import React, { Component } from 'react';
import Button from './Button'
import Sidebar from './Sidebar'
class App extends Component {
sidebar = React.createRef()
state = {
toggle: false,
menus: [
{
icon: '♜',
title: 'HOME'
},
{
icon: '♞',
title: 'ABOUT'
},
{
icon: '☻',
title: 'SETTING'
},
{
icon: '♜',
title: 'HOME'
},
{
icon: '♞',
title: 'ABOUT'
},
{
icon: '☻',
title: 'SETTING'
}
]
}
toggleMenu = () => {
this.setState({toggle: !this.state.toggle})
}
hideSideBar = () => {
this.setState({ toggle: false })
}
closeSideBar = (e) => {
console.log(this.sidebar.current)
console.log(this.state.toggle)
console.log(e.target)
if(this.state.toggle && !e.target.classList.contains(this.sidebar.current)){
this.hideSideBar()
}
}
componentDidMount(){
window.addEventListener('click', this.closeSideBar, true) // 버블링 방지
}
componentWillUnmount(){
window.removeEventListener('click', this.closeSideBar, true) // 버블링 방지
}
render(){
const { toggle, menus } = this.state
return (
<div className="App">
<Button handleClick={this.toggleMenu}>Open sidebar</Button>
<Sidebar open={toggle} ref={this.sidebar}>
{menus.map( (menu, id) => {
return <div className="menu" key={id} onClick={this.hideSideBar}>{menu.icon} {menu.title} </div>
})}
</Sidebar>
</div>
);
}
}
export default App;
window.addEventListener 와 window.removeEventListener 의 세번째 인자에 true 를 설정하지 않으면 Open sidebar 버튼을 클릭할때 이벤트가 부모 엘리먼트까지 버블링되기 때문에 closeSideBar 함수가 실행된다. 이렇게 되면 hideSideBar 함수가 연속적으로 실행되면서 사이드바가 열리자마자 닫힌다. 사용자의 눈에는 보이지 않는다.
부모 컴포넌트에서 자식 컴포넌트인 Sidebar 에 직접 접근하는 경우에는 위와 같이 createRef 메서드로 참조변수를 생성한 다음 참조할 컴포넌트에 ref props 로 전달한다.
import React from 'react'
import './Sidebar.css'
const Sidebar = React.forwardRef(({ open, children }, ref) => {
return (
<div className={`sidebar ${open? 'open': ''}`} ref={ref}>
<div className="sidebar-menus">{children}</div>
</div>
)
})
export default Sidebar
그런 다음 위와 같이 forwardRef 메서드로 참조할 컴포넌트를 감싸준다. 그리고 컴포넌트에 ref props 를 전달받아서 직접 접근하려는 엘리먼트에 ref 로 설정해준다.
728x90
'프론트엔드 > React 연습과제 해답' 카테고리의 다른 글
리액트 기초이론 8 - 리액트 라우터 해답 (0) | 2022.03.15 |
---|---|
리액트 기초이론 9 - 리액트 훅(React Hook) 해답 (0) | 2022.03.15 |
리액트 기초이론 5 - 컴포넌트 스타일링 3 - Styled Components 해답 (0) | 2022.03.07 |
리액트 기초이론 5 - 컴포넌트 스타일링 2 - SASS 해답 (0) | 2022.03.02 |
리액트 기초이론 5 - 컴포넌트 스타일링 해답 (0) | 2022.02.28 |