컴포넌트끼리 값을 주고 받기
import React, { useState } from 'react'
import Ex09Item from './components/Ex09Item'
const Ex09 = () => {
/*
컴포넌트끼리 값을 주고 받기
- Ex09.jsx : 상위 요소 (부모)
- components -> Ex09Item.jsx : 하위 요소 (자식)
** 상위에서 하위로! 실습
1. input에 onChange 이벤트를 걸어준다 => changeData 함수 실행
2. 이벤트 객체를 받아와서 사용자의 입력값을 console에 확인
3. inputTitle이라는 state에 해당 입력값을 세팅
4. inputTitle이라는 state 값을 Ex09Item에게 전달 - props
5. 입력할 때 마다 어쩌고저쩌고 대신 나의 입력값이 들어가도록
*/
const [inputTitle, setInputTitle] = useState("");
const changeData = (e)=>{
console.log(e.target.value);
setInputTitle(e.target.value);
}
// ---------------------------------------------------------
const [childTitle, setChildTitle] = useState("");
const chageDataFromChild = (data) => {
console.log('chageDataFromChild Function Called', data);
setChildTitle(data)
}
return (
<div>
<h1>양방향 데이터 통신</h1>
<h3>상위에서 하위로</h3>
<input type='text' onChange={changeData}></input>
<Ex09Item text={inputTitle} chageDataFromChild={chageDataFromChild}/>
<span>하위에서 상위로 넘어온 값은 {childTitle} 입니다.</span>
</div>
)
}
export default Ex09
import React from 'react'
const Ex09Item = ({text, chageDataFromChild}) => {
return (
<div>
상위 컴포넌트에서 입력받은 값은 {text} 입니다.
<hr/>
<h3>하위에서 상위로</h3>
<input type='text' onChange={(e)=>{
chageDataFromChild(e.target.value)
}}/>
</div>
)
}
export default Ex09Item






색상 클릭 시 밑에 색상 클릭한 색상으로 바뀌기



import React, { useState } from 'react'
import { colorContext } from './context/Ex10ColorContext'
import ColorList from './components/Ex10/ColorList'
import ColorResult from './components/Ex10/ColorResult'
const Ex10 = () => {
/*
Context 란?
- 리액트 컴포넌트 간에 값을 전역적으로 공유할 수 있게 해주는 기능
- 우리에게는 데이터를 주고받는 props가 있는데 왜 context를 써야하는가?
A. props로만 데이터를 전달하면 깊숙하게 위치한 컴포넌트에 데이터를 전달하는 경우
여러번 연달아서 props를 설정하게 됨 => 불편하고, 실수가 잦음
이러한 현상을 props drilling 이라고 부른다.
그래서 우리는 context로 전역적으로 데이터를 관리한다.
[Context 만드는 순서]
1) context 파일을 만들어준다.
- createContext
- 꼭! export 해주기
2) context를 사용할 공간에 import {context} 해주기!
3) context Provider로 감싸주기
- Provider 안에 value라는 속성
- value 안에 우리가 전달하고자 하는 데이터, 저장하고자 하는 데이터 등등을 넣는다.
*/
const [choiceColor, setChoiceColor] = useState('red');
return (
<colorContext.Provider value={{choiceColor, setChoiceColor}}>
<h1>변경할 색상을 고르시오.</h1>
<ColorList/>
<hr/>
<h1>선택한 색상은</h1>
<ColorResult/>
</colorContext.Provider>
)
}
export default Ex10
import { createContext } from 'react';
export const colorContext = createContext(null);
import React, { useContext } from 'react'
import { colorContext } from '../../context/Ex10ColorContext'
const ColorList = () => {
let color = ["red", "orange", "yellow", "green", "blue"]
const {setChoiceColor} = useContext(colorContext)
const colorClick = (e) => {
console.log(e.target.style.backgroundColor);
setChoiceColor(e.target.style.backgroundColor)
}
return (
<div style={{display : 'flex'}}>
{color.map(item => (
<div
key={item}
style={{
width : "100px",
height : "100px",
background : `${item}`
}
} onClick={colorClick}/>
))}
</div>
)
}
export default ColorList
import React, { useContext } from 'react'
import { colorContext } from '../../context/Ex10ColorContext'
const ColorResult = () => {
const {choiceColor} = useContext(colorContext)
return (
<div style={{
width : '100px',
height : '100px',
background : `${choiceColor}`
}}>
</div>
)
}
export default ColorResult



다크모드



import React, { useState } from 'react'
import { ThemeContext } from './context/Ex11ThemeContext'
import Header from './components/Ex11/Header'
import Content from './components/Ex11/Content'
import Footer from './components/Ex11/Footer'
import './ex11.css'
const Ex11 = () => {
const [darkMode, setDarkMode] = useState(false);
return (
<div>
<ThemeContext.Provider value={{darkMode, setDarkMode}}>
<Header/>
<Content/>
<Footer/>
</ThemeContext.Provider>
</div>
)
}
export default Ex11
* {
box-sizing: border-box;
margin: 0;
font-family: sans-serif;
}
.page {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
}
.header {
width: 100%;
height: 80px;
border-bottom: 2px solid gray;
display: flex;
justify-content: center;
align-items: center;
}
.content {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
font-size: 30px;
}
.footer {
width: 100%;
height: 80px;
border-top: 2px solid gray;
display: flex;
justify-content: flex-end;
align-items: center;
}
.button {
padding: 10px;
margin-right: 30px;
}
import { createContext } from "react";
export const ThemeContext = createContext(null);
import React, { useContext } from "react";
import { ThemeContext } from "../../context/Ex11ThemeContext";
const Header = () => {
const {darkMode} = useContext(ThemeContext)
return (
<header
className="header"
style={{
backgroundColor: darkMode ? "black" : "skyblue",
color: darkMode ? "white" : "black"
}}
>
<h1>스마트인재개발원</h1>
</header>
);
};
export default Header;
import React, { useContext } from "react";
import { ThemeContext } from "../../context/Ex11ThemeContext";
const Content = () => {
const {darkMode} = useContext(ThemeContext)
return (
<div
className="content"
style={{
backgroundColor: darkMode ? "black" : "white",
color: darkMode ? "white" : "black",
}}
>
<h1>지각하지 않기! 결석하지 않기!</h1>
</div>
);
};
export default Content;
import React, { useContext } from "react";
import { ThemeContext } from "../../context/Ex11ThemeContext";
const Footer = () => {
const {darkMode, setDarkMode} = useContext(ThemeContext)
const toggleTheme = () => {
console.log('darkMode', darkMode);
setDarkMode(!darkMode)
// setDarkMode(darkMod ? false : true)
// if(darkMode == false){
// setDarkMode(true)
// }else {
// setDarkMode(false)
// }
};
return (
<div>
<footer
className="footer"
style={{
backgroundColor: darkMode ? "black" : "lightgray"
}}
>
<button className="button" onClick={toggleTheme}>
{darkMode ? <sapn>Light Mode</sapn> : <sapn>Dark Mode</sapn>}
</button>
</footer>
</div>
);
};
export default Footer;


Todo List





import React, { useState } from 'react'
import { TodoContext } from './context/Ex12TodoContext'
import List from './components/Ex12/List'
import AddItem from './components/Ex12/AddItem'
import './ex12.css'
const Ex12 = () => {
/** 할 일 리스트가 누적되어있는 배열 (state 형식) */
const [todos, setTodos] = useState([
{text : "물 마시기", completed : false, key : 1}
]);
// STEP 1. 할 일 추가하기
const [newTodo, setNewTodo] = useState("");
/** 새로운 newTodo 데이터를 todos 배열에 추가하는 함수 */
const handleNewTodoAddition = () => {
console.log('handleNewTodoAddition function', newTodo)
setTodos([
...todos,
{text : newTodo,
completed : false,
key : todos[todos.length-1].key + 1
}
]);
setNewTodo("")
}
/** todolist를 삭제시켜 줄 함수 */
const handleTodoDelete = (delKey) => {
console.log('handleNewTodoDelete function', delKey)
const filteredList = todos.filter(item => item.key !== delKey)
setTodos(filteredList)
}
/** 완료한 한 일에 체크 혹은 반대의 경우 체크 해제 toggle 함수 */
const handleTodoToggle = (ckKey) => {
console.log('handleTodoToggle function', ckKey);
// * find 배열함수
let targetTodo = todos.find(item => item.key == ckKey)
console.log('targetTodo', targetTodo);
if(targetTodo) {
targetTodo.completed = !targetTodo.completed
setTodos([...todos])
}
}
return (
<TodoContext.Provider value={{todos,
newTodo,
setNewTodo,
handleNewTodoAddition,
handleTodoDelete,
handleTodoToggle}}>
<div className='todo-container'>
<h1>📃TODO LIST🖊</h1>
<List/>
<AddItem/>
</div>
</TodoContext.Provider>
)
}
export default Ex12
@font-face {
font-family: "GmarketSansMedium";
src: url("https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2001@1.1/GmarketSansMedium.woff")
format("woff");
font-weight: normal;
font-style: normal;
}
* {
font-family: "GmarketSansMedium";
}
.todo-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-image: linear-gradient(120deg, pink 0%, #c2e9fb 100%);
border-radius: 20px;
margin: 3%;
padding: 10%;
box-sizing: border-box;
}
h1 {
font-weight: 900;
}
li {
list-style: none;
}
button {
height: 30px;
font-size: 0.8em;
background-color: rgb(231, 181, 190);
border: 0px;
}
input[type="checkbox"] {
margin: 3%;
}
li{
display: flex;
align-items: center;
justify-content: center;
}
.todo-text{
/* background-color: red; */
width: 300px;
display: block;
}
.list-container{
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
input[type="text"]{
width: 300px;
}
import { createContext } from "react";
export const TodoContext = createContext(null);
import React, { useContext } from 'react'
import { TodoContext } from '../../context/Ex12TodoContext'
import ListItem from './ListItem';
const List = () => {
const {todos} = useContext(TodoContext)
console.log('todos', todos);
return (
<div>
<table>
<tbody>
{todos.map(item => <ListItem key={item.key} todo={item}/>)}
</tbody>
</table>
</div>
)
}
export default List
import React, { useContext } from 'react'
import { TodoContext } from '../../context/Ex12TodoContext'
const AddItem = () => {
const {newTodo, setNewTodo, handleNewTodoAddition} = useContext(TodoContext)
return (
<div>
<input value={newTodo} type='text' onChange={(e)=>{setNewTodo(e.target.value)}}/>
<button onClick={handleNewTodoAddition}>Add</button>
</div>
)
}
export default AddItem
import React, { useContext } from 'react'
import { TodoContext } from '../../context/Ex12TodoContext'
const ListItem = ({todo}) => {
const {handleTodoDelete, handleTodoToggle} = useContext(TodoContext)
return (
<>
<tr>
<td><input type='checkbox' checked={todo.completed} onChange={()=>{handleTodoToggle(todo.key)}}/></td>
<td>
<label style={{
textDecoration : todo.completed ? "line-through" : "none"
}}>
<span className='todo-text'>{todo.text}</span>
</label>
</td>
<td><button onClick={()=>{handleTodoDelete(todo.key)}}>Delete</button></td>
</tr>
</>
)
}
export default ListItem



