안녕하세요 상훈입니다.

드림코딩 앨런님의 강의로 자바스크립트를 이용하여 짧고 간단한 쇼핑 웹앱을 구현하도록 해보겠습니다.

결과 화면

 

index.html

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="style.css">
  <script src="src/main.js" defer></script>
  <title>Document</title>
</head>
<body>
  <!--Logo-->
  <img src="img/logo.png" alt="Logo" class="logo">

  <!--Buttons-->
  <div class="buttons">
    <button class="btn">
      <img src="img/blue_t.png" alt="blue tshirts" class="imgBtn" data-key="type" data-value="tshirt" />
    </button>
    <button class="btn">
      <img src="img/blue_p.png" alt="blue pants" class="imgBtn" data-key="type" data-value="pants" />
    </button>
    <button class="btn">
      <img src="img/blue_s.png" alt="blue skirt" class="imgBtn" data-key="type" data-value="skirt" />
    </button>
    <button class="btn" class="btn colorBtn blue"  data-key="color" data-value="blue">Blue</button>
    <button class="btn" class="btn colorBtn yellow" data-key="color" data-value="yellow">Yellow</button>
    <button class="btn" class="btn colorBtn pink" data-key="color" data-value="pink">Pink</button>
  </div>
  <!--Items-->
  <ul class="items"></ul>
</body>
</html>

 

 

main.js

// Fetch the items from the JSON file
function loadItems() {
    return fetch('data/data.json')
    .then(response => response.json())
    .then(json => json.items)
}

// update the list with the given items
function displayItems(items) {
    const container = document.querySelector('.items')
    container.innerHTML = items.map(item => createHTMLString(item)).join('')
}

// Create html list item from the given data item
function createHTMLString (item) {
    return `
        <li class="item">
            <img src="img/${item.image}" alt="${item.type}" class="item__thumbnail">
            <span class="item__description">${item.gender}, ${item.size}</span>
        </li>
    `
}

function onButtonClick (event, items) {
    const dataset = event.target.dataset
    const key = dataset.key
    const value = dataset.value

    if(key == null || value == null){
        return ;
    }

    // updateItems(items, key, value)

    const filtered = items.filter(item => item[key] === value)
    displayItems(filtered)
}

function updateItems(items, key, value) {
    items.forEach(item => {
        if(item.dataset[key] === value) {
            item.classList.remove('invisiable')
        }else{
            item.classList.add('invisable')
        }
    });
}


function setEventListeners (items) {
    const logo = document.querySelector('.logo')
    const buttons = document.querySelector('.buttons')
    logo.addEventListener("click", () => displayItems(items) )
    buttons.addEventListener("click", event => onButtonClick(event, items))
}


// main
loadItems() 
    .then(items => {
        displayItems(items)
        setEventListeners(items)
    })
    .catch(console.log)

 

 

style.css

:root {
  /* color */
  --color-black: #3f454d;
  --color-white: #ffffff;
  --color-blue: #3b88c3;
  --color-yellow: #fbbe28;
  --color-pink: #fd7f84;
  --color-light-grey: #dfdfdf;

  /* size */
  --base-space: 8px;
  --size-button: 60px;
  --size-border: 4px;
  --size-thumbnail: 50px;
  --font-size: 18px;

  /* animation */
  --animation-duration: 300ms;
}

body {
  height:100vh;
  background-color: var(--color-black);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.logo {
  cursor: pointer;
  transition: transform var(--animation-duration) ease;
}

.btn {
  background-color: transparent;
  border: none;
  outline: none;
  cursor: pointer;
  transition: transform var(--animation-duration) ease;
  margin-right: var(--base-space);
}

.btn:hover,
.logo:hover {
  transform: scale(1.1);
}

.buttons {
  display: flex;
  align-items: center;
}

.imgBtn {
  width: var(--size-button);
  height:var(--size-button);
}

.colorBtn {
  font-size: var(--font-size);
  padding: calc(var(--base-space) * 2);
  border-radius: var(--size-border);
}

.blue {
  background-color: var(--color-blue);
}

.yellow {
  background-color: var(--color-yellow);
}

.pink {
  background-color: var(--color-pink);
}

.items {
  width: 60%;
  height: 60%;
  list-style: none;
  padding-left:0;
  overflow-y: scroll;
}

.item {
  background-color: var(--color-white);
  display: flex;
  align-items: center;
  padding: var(--base-space);
  margin-bottom: var(--base-space);
}

.item__thumbnail {
  width: var(--size-thumbnail);
  height: var(--size-thumbnail);
}

.item__description {
  margin-left: var(--base-space);
  font-size: var(--font-size);
}

 

디렉터리 구조

디렉터리 구조는 다음과 같습니다. 강의 영상에서 제공한 project 자체를 import 시켰습니다.

이미지, json 등의 파일은 모두 구비되었습니다.

 

강의 진행이 되면서 간단하다 간단하다 하셨는데, 전혀 간단하게 느껴지지 않았습니다. ㅠㅠ

자바스크립트의 filter, map 등등 몇가지 라이브러리를 사용하셨었는데, 

저같은 웹린이한테는 어렵다고 느껴졌어요...

눈물..

나는 감자다! I'm annoied talking potatoooooooo!!!!

 

반응형

안녕하세요 상훈입니다.

리액트 - 차트를 이용해 코로나19의 현황을 간단하게 알아보는 예제를 출력하겠습니다.

결과화면

Contents.js

import React, {useState, useEffect} from 'react'
import { Bar, Doughnut, Line } from "react-chartjs-2"
import axios from 'axios'


const Contents = () => {

    const [confirmedData, setConfirmedData] = useState({})
    const [quarantinedData, setQuarantinedData] = useState({})
    const [comparedData, setComparedData] = useState({})




    useEffect(() => {
        const fetchEvents = async () => {
            const res = await axios.get("https://api.covid19api.com/total/dayone/country/kr")
            console.log(res)
            makeData(res.data)

        }
        const makeData = (items)=>{
            const arr = items.reduce((acc, cur) => {
                const currentDate = new Date(cur.Date)
                const year = currentDate.getFullYear()
                const month = currentDate.getMonth()
                const date = currentDate.getDate()
                const confirmed = cur.Confirmed
                const active = cur.Active
                const death = cur.Death
                const recovered = cur.Recovered

                const findItem = acc.find(a=> a.year === year && a.month === month)

                if(!findItem){
                    acc.push({ year, month, date, confirmed, active, death, recovered })
                }
                if(findItem && findItem.date < date){
                    findItem.active = active
                    findItem.death = death
                    findItem.date = date
                    findItem.year = year
                    findItem.month = month
                    findItem.recovered = recovered
                    findItem.confirmed = confirmed

                }
                return acc;

            }, [])


            const labels = arr.map(a => `${a.month+1}월`)
            setConfirmedData({
                labels,
                datasets: [
                    { 
                        label: "국내 누적 확진자", 
                        backgroundColor: "salmon",
                        fill: true,
                        data: arr.map(a => a.confirmed)
                    },
                ]
            })

            setQuarantinedData({
                labels,
                datasets: [
                    { 
                        label: "월별 격리자 현황", 
                        borderColor: "salmon",
                        fill: false,
                        data: arr.map(a => a.active)
                    },
                ]
            })

            const last = arr[arr.length -1 ]
            setComparedData({
                labels: ["확진자","격리해제","사망"],
                datasets: [
                    { 
                        label: "누적 확진, 해제, 사망 비율", 
                        backgroundColor: ["#ff3d67", "#059bff", "#ffc233"],
                        borderColor: ["#ff3d67", "#059bff", "#ffc233"],
                        fill: false,
                        data: [last.confirmed, last.recovered, last.death]
                    },
                ]
            })
        }
        fetchEvents()
    }, [])

    return (
        <section>
            <h2>국내 코로나 현황</h2>
            <div className="contents">
                <div>
                    <Bar data={confirmedData} options={
                        {title: { display : true, text: "누적 확진자 추이", fontSize: 16 } },
                        {legend: {display : true, position: "bottom"} }
                    } />
                </div>
                <div>
                    <Line data={quarantinedData} options={
                        {title: { display : true, text: "월별 격리자 현황", fontSize: 16 } },
                        {legend: {display : true, position: "bottom"} }
                    } />
                </div>
                <div>
                    <Doughnut data={comparedData} options={
                        {title: { display : true, text: `누적 확진, 해제, 사망 (${new Date().getMonth() + 1 })`, fontSize: 16 } },
                        {legend: {display : true, position: "bottom"} }
                    } />
                </div>
            </div>
        </section>
    )
}

export default Contents

 

 

App.css

.App {
  display: flex;
  flex-direction: column;
}

.header {
  background-color: #3b5998;
  display: flex;
  justify-content: space-between;
  padding: 1rem 2rem;
  align-items: center;
}

.header h1{
  color:azure;
}

.header select {
  height: 30px;
  width: 140px;
  border-radius: 5px;
  border: none;
}

section {
  padding: 1rem;
}

.contents {
  width: 60%;
  text-align:center;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-gap : 2rem;
}

 

원형차트는 아무래도 확진자 대비 나머지 비율이 너무 작아서 안보이는 건지,,,, 아니면 제가 api 적용을 잘못한건지 헷갈립니다... ㅠㅠ

나중에 확인 해야할 것 같아요. 그럼 이만ㅌㅌ

 

 

강의 참고

React.js로 웹앱 만들기

 

리액트와 가까워지기.
(어렵당)

 

반응형

안녕하세요 상훈입니다.

리액트에서 Axios 요청을 사용하는 방법(chart ... etc)을 알아보도록 하겠습니다.

$ npm install axios react-chartjs-2 --save

터미널에 복사 붙여넣기 해주시면 됩니다.

 

Axios는 js의 Ajax와 유사합니다.

브라우저와 Node.js에서 Promise API를 통신 방식으로서,

 프론트와 백을 연결하여 HTTP 비동기 통신 방식입니다.

 

받아오는 방식은 JSON 입니다.

이 중에 GET 방식을 진행해볼건데, 

axios.get(url)

로 사용이 가능합니다. 

 


예제) 코로나 현황 검색

우리나라의 covid19 현황을 검색해보겠습니다.

저는 Google Extensions : Talend API Tester를 사용했구요, api 통신 테스터 아무거나 사용하셔도 무방합니다.

api 테스트 send 작업 - 우리나라 코로나 현황
결과값

이렇게 JSON 형태로 값이 받아와졌습니다. 

이제 web에 적용을 하도록 하겠습니다.

Contents.js    :  React.js file

import React, {useState, useEffect} from 'react'
import axios from 'axios'


const Contents = () => {

    useEffect(() => {
        const fetchEvents = async () => {
            const res = await axios.get("https://api.covid19api.com/total/dayone/country/kr")
            console.log(res)
        }
        fetchEvents()
    })

    return (
        <section>
            <h2>국내 코로나 현황</h2>
            <div className="contents">
            

            </div>
        </section>
    )
}

export default Contents

 

1. useState와 useEffect를 import 해주셔서 앱이 로딩이 될 때 사용을 하도록 하고,

2. axios를 import하여 axios를 사용할 수 있게 해줍니다.

3. 그리고 async await을 사용하여 바로 스크립트가 실행되는 것이 아닌, 먼저 모든 페이지가 로딩 된 후에 데이터를 찾는 것으로 설정하였습니다.

 

console창 확인

 

이렇게 object 형태로 데이터를 받아왔습니다.

 

반응형

 

리액트 코드를 작성하면서 snippets가 작용할 수 있게.

= h1 만 작성하여도 자동으로 <h1></h1>이 작성되게 하는 익스텐더

 

 

반응형

안녕하세요 상훈입니다.

자바스크립트로 문자열을 나누는 split 함수를 사용하도록 하겠습니다.

<script>
  cosnt yearInput = prompt('태어난 해는?', '')
  const year = Number(yearInput)
  const tags = '원숭이,닭,개,돼지,쥐,소,호랑이,토끼,용,뱀,말,양'.split(',')
  alert(`${year}년에 태어났다면, ${tags[year%12]} 띠 입니다.`)
</script>

결과

 

Split 함수 예제를 알아보았습니다.

반응형

안녕하세요 상훈입니다.

리액트 훅으로 useEffect를 사용하여 웹페이지 접속 3초 후Title 부분이 바뀌는 예제를 작성하도록 하겠습니다.

App.js

import React, {useState, useEffect } from "react";

const useTitle = initialTitle => {
  const [title, setTitle] = useState(initialTitle)
  const updateTitle = () => {
    const htmlTitle = document.querySelector("title")
    htmlTitle.innerText = title
  }
  useEffect(updateTitle, [title])
  return setTitle
}


function App() {
  const titleUpdater = useTitle("Loading...")  // 시작할 때
  setTimeout(()=> titleUpdater("Home"), 3000)  // 3초 후 

  return (
    <div className="App">
      <div>Hi</div>    
    </div>
  );
}

export default App;

Loading... -> 3초후 -> Home 

으로 바뀌는 페이지 제목을 확인하실 수 있습니다.

결과 화면 캡쳐
끝~!!

 

 

강의 참고 : 니콜라스님

 

All Courses – 노마드 코더 Nomad Coders

초급부터 고급까지! 니꼬쌤과 함께 풀스택으로 성장하세요!

nomadcoders.co

 

 

 

반응형

안녕하세요 상훈입니다.

리액트 훅에서 useState를 활용한 증가버튼, 감소버튼을 구현하도록 하겠습니다.

1. index.js 

import React, { useState } from "react";

const App = () => {

  const [item, setItem] = useState(0)
  const incrementItem = () => setItem(item + 1)
  const decrementItem = () => setItem(item - 1)

  return (
    <div className="App">
      <h1>Hello {item}</h1>
      <h2>Start editing to see some magic happen!</h2>
      <button onClick={incrementItem}>Increment</button>
      <button onClick={decrementItem}>Decrement</button>

    </div>
  )

}

export default App;

 

useState() 를 이용하는건, 생각보다 단순하지만,

일일이 값을 생성하고 지정해주어야하는 번거로움이 존재한다. 

 

result

 

 

반응형

안녕하세요 상훈입니다.

코드 샌드박스 같은 곳이 아니라 내 로컬 디스크에 있는 vscode에서 리액트 훅을 공부해보고 싶었습니다.

 

1. 터미널에서 프로젝트를 명령어로 생성해줍니다.

$ npx create-react-app hooks-react

"hooks-react"라는 폴더명으로 프로젝트가 생성됩니다.

 

2. 기본 작성되어진 html을 지우기 위해서 src 폴더 내에 있는 App.js와 index.js 이외의 모든 파일을 지우도록 하겠습니다.

App.js, index.js 이외 모두 삭제

 

3. App.js

import React from "react";
const App = () => <div>Hello React?</div>;
export default App;

index.js

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";

ReactDOM.render(<App />, document.getElementById("root"));

기존의 내용을 삭제해주시고, 변경해줍니다.

 

4. 터미널에서 시작을 해줍시다.

$ npm start

 

npm run successed!

 

5. 결과 확인.

아까 작성하였던 <div>Hello React?</div> 에 의해 

localhost:3000

"Hello React?" 라는 문구가 포트3000번localhost 에서 출력이 됩니다.

 

 

 

1단계리액트-훅 프로젝트 구동에 대해 알아봤습니다.

 

React-hooks 기본01. 프로젝트 구동

 

참고

 

[리액트 초보 따라하기 / To do] 1. create-react-app으로 프로젝트 생성하기

React로 어플리케이션을 개발할 때에는 관련 패키지 설치 및 webpack, babel 설정과 같이 까다로운 과정이 많습니다. 페이스북에서는 개발자가 어플리케이션 개발에만 집중할 수 있도록

codingbroker.tistory.com

 

반응형

+ Recent posts