기업협업 작업을 위해 사용했던 라이브러리이다.
형태와 기능은 input 태그의 range 타입과 같다.
가격필터를 위해 사용했다.
(처음에는 체크박스로 가격을 필터하려고 했으나,
제품마다 가격이 너무 달랐고 무엇보다 기업에서 슬라이더 형태를 원하여 슬라이더 형태를 사용했다)
아무튼 기업협업을 하며 slick과 loading indicator 라이브러리를 사용해서
나름 라이브러리를 이제 이해하고 있었구나라는 나의 생각을 처절하게 짓밟아주었다.
이전에 썼던 slick 글에서 openbase를 찬양했다.
그러나 이번엔 딱 마음에 드는 라이브러리를 찾지 못 했다.(내 검색이 틀렸을 수도 있다.)
그래서 주변에 물어보고 귀동냥하여 Material-UI 에 대해 알게 되었다.
리액트 사용자를 위한 UI Framework라고 한다.
Material-UI
React components for faster and easier web development.
Build your own design system, or start with Material Design.출처: 공식페이지
공식페이지에 아주 설명이 잘 되어있다. 나한테만 안 유명하고 아주 유명한 것처럼 보인다.
npm설치하기
npm install @material-ui/core
Roboto Font 사용하기.
Roboto font를 사용하여 UI를 제작했다고 한다. 그러니 꼭 써야한다.
<html>
<head>
..생략
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
..생략
</head>
이외에도 Font Icons나 SVG Icons 설치에 대한 설명이 있으니 꼭 하자.
아마 하지 않으면 아수라장을 경험할 수도 있다.
개인적으로 라이브러리를 처음 쓸 때는 docs에서 하라는 대로 하는 편이다.
내 것으로 적용하기 전에 일단 화면에 한 번 띄어본다.
material-ui 에서 사용하려는 가격 슬라이더의 형태는 앞서 말했듯이 input 태그의 range 타입이다.
따라서, Components - Inputs - Slider(슬라이더로 되어있다)로 찾아가면 여러가지 모습의
슬라이더 예시와 이를 만들기 위한 코드가 친절히 작성되어 있다.
가격 필터로 사용해야 하기 때문에 가격의 범위가 있어야 한다.
그래서 기준점(?)이 두 개인 슬라이더가 필요하다.
material-ui에선 이를 Range slider라고 부른다. 내가 원하는 모양을 하고 있다.
코드는 다음과 같다.
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
import Slider from '@material-ui/core/Slider';
const useStyles = makeStyles({
root: {
width: 300,
},
});
function valuetext(value) {
return `${value}°C`;
}
export default function RangeSlider() {
const classes = useStyles();
const [value, setValue] = React.useState([20, 37]);
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<div className={classes.root}>
<Typography id="range-slider" gutterBottom>
Temperature range
</Typography>
<Slider
value={value}
onChange={handleChange}
valueLabelDisplay="auto"
aria-labelledby="range-slider"
getAriaValueText={valuetext}
/>
</div>
);
}
앞서 다른 라이브러리를 써서 그런지,
아니면 제공하는 곳에서 이해하기 좋게 코드를 썼는지는 모르겠지만
이제 어느 정도 이해가 된다.
<Slider />
에 함수와 이 부분만을 위한 css 속성이 있다.화면에 띄어본다. 예시와 같다. 이제 사용하면 된다.
처음 생각
앙증맞다. 아주 깜찍하다. 정말 머리 좋은 사람들은 다르다.
이렇게 사용하기 편하게 만들어 놓다니. 이것이 개발자의 세계인가. 라는 생각으로 신나게 시작했다.
문제 발생
절망적이었다. docs를 계속 보고 수정했다. 영어였다.
(해외의 수많은 라이브러리 docs를 번역해주는 국내 사이트가 있다면 대박이 날 것이다.)
문제 해결
내가 작성한 코드는 다음과 같다.(리액트와 스타일 컴포넌트를 사용했다.)
import React, { Component, useState, useEffect } from "react";
import styled from "styled-components";
import { makeStyles } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import Slider from "@material-ui/core/Slider";
import { TextareaAutosize } from "@material-ui/core";
// 최초 코드가 작성해준 스타일부분(건드려도 됨)
const useStyles = makeStyles({
root: {
width: 300,
},
});
// 최초 코드가 작성해준 함수(사용하지 않음)
function valuetext(value) {
return `${value}원`;
}
//컴포넌트 선언
const Price = () => {
const classes = useStyles();
const [value, setValue] = useState([]); //값
const [min, setMin] = useState();
const [max, setMax] = useState();
useEffect(() => {
fetch("http://localhost:3000/data/data.json")
.then((res) => res.json())
.then((res) => {
// data 중 가격으로만 이루어진 새로운 배열 생성
const price = res.data.map((data) => data.price);
// 가격으로 이루어진 배열에서, 최대값과 최소값 구하기
const max = price.reduce(function (pre, cur) {
return pre > cur ? pre : cur;
});
const min = price.reduce(function (pre, cur) {
return pre > cur ? cur : pre;
});
setData(res.data);
// 최소값과 최대값으로 defaultValue 값 설정
setValue([min, max]);
setMin(min);
setMax(max);
});
},[]);
// 슬라이더를 변화시킬 때 마다 value 값 조정
const handleChange = (event, newValue) => {
setValue(newValue);
};
//천단위 , 찍기 위한 함수
const numberFormat = (num) => {
if (num > 1000) {
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
} else {
return "0";
}
};
return (
<Wrap>
<div className={classes.root}>
<TextWrap>
<Text>가격대</Text>
<PriceInfo>
{numberFormat(value[0])}원 ~ {numberFormat(value[1])}원
</PriceInfo>
</TextWrap>
<Slider
value={value} //가격 슬라이더의 값
defaultValue={[min, max]} //가격 슬라이더 최초 범위
onChange={handleChange} //슬라이더 변할 때마다 value값을 조정하는 함수
aria-labelledby="range-slider" //슬라이더 형태
max={max}
min={min}
stpe="10000" //이동 단위(?)
/>
</div>
</Wrap>
);
};
export default Price;
fetch부분
<Slider />
부분
이렇게 하면 움직인다. 슬라이더가 움직이고 그 범위의 시작과 끝(최소값과 최대값)을
console에 찍어보면 기가막히게 들어온다. 이제 이를 사용하여 필터를 쓰면 될 것이다.
(아마 슬라이더가 움직일 수 있는 default 값을 지정해줘야 하는 것 같다.)
확실한 방법은 아니다. 교과서적인 방법은 아니다.
이제 value 값이 이쁘게 찍히니 빠른 속도로 코드를 쓸 수 있을 것이라 생각했다.
실패했다. 그러나 하긴 했다.
코드는 다음과 같다.
import React, { Component, useState, useEffect } from "react";
import styled from "styled-components";
import { makeStyles } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import Slider from "@material-ui/core/Slider";
import { TextareaAutosize } from "@material-ui/core";
const useStyles = makeStyles({
root: {
width: 300,
},
});
function valuetext(value) {
return `${value}원`;
}
const Price = () => {
const classes = useStyles();
const [value, setValue] = useState([]);
const [curVal, setCur] = useState([]);
const [min, setMin] = useState();
const [max, setMax] = useState();
const [data, setData] = useState();
const [ren, setRen] = useState(true);
useEffect(() => {
fetch("http://localhost:3000/data/data.json")
.then((res) => res.json())
.then((res) => {
// data 중 가격으로만 이루어진 새로운 배열 생성
const price = res.data.map((data) => data.price);
// 가격으로 이루어진 배열에서, 최대값과 최소값 구하기
const max = price.reduce(function (pre, cur) {
return pre > cur ? pre : cur;
});
const min = price.reduce(function (pre, cur) {
return pre > cur ? cur : pre;
});
setData(res.data);
// 최소값과 최대값으로 defaultValue 값 설정
setValue([min, max]);
setMin(min);
setMax(max);
//////가격 필터//////////
if (curVal.length > 0) {
const priceData = res.data.filter(
(data) => curVal[0] <= data.price && data.price <= curVal[1]
);
setData(priceData);
setValue([curVal[0], curVal[1]]);
}
});
}, [ren]);
// 슬라이더를 변화시킬 때 마다 value / CurValue 값 조정 (CurValue 값을 조정해야한다.)
const handleChange = (event, newValue) => {
setValue(newValue);
setCur(newValue);
};
//componentDidUpdate를 위한 state값 변화
const handleFilter = () => {
setRen(!ren);
};
//천단위 , 찍기 위한 함수
const numberFormat = (num) => {
if (num > 1000) {
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
} else {
return "0";
}
};
return (
<Wrap>
<div className={classes.root}>
<TextWrap>
<Text>가격대</Text>
<PriceInfo>
{numberFormat(value[0])}원 ~ {numberFormat(value[1])}원
</PriceInfo>
</TextWrap>
<Slider
value={value} //가격 슬라이더의 값
defaultValue={[min, max]} //가격 슬라이더 최초 범위
onChange={handleChange} //슬라이더 변할 때마다 value값을 조정하는 함수
aria-labelledby="range-slider" //슬라이더 형태
max={max}
min={min}
stpe="10000" //이동 단위(?)
/>
</div>
<div onClick={() => handleFilter()}>제품보기</div>{" "}
{/* state값 변화시켜 새로 render하기 */}
</Wrap>
);
};
export default Price;
해결해야할 것들
해결 방안
이렇게 했다.
이게 필터의 정석인가. 아닐 것 같은데.
뭔가 훨씬 더 세련된 코드가 있을 것 같다. 일단은 동작한다. 끝.
글을 쓰면서 계속 라이브러리라고 했는데
material-ui 는 프레임워크다.
이게 뭐랄까.
아는게 많아서 먹고 싶은 것도 많겠네
라는 말이 있는 것처럼 알고 있는게 많아야(뭐든) 시간이 줄어든다.
여기서 시간은 검색시간이다.
라이브러리는 프레임워크든 아직은 다 생소해서 뭘 찾아야 할지 모른다.
그러나 극복한다.
ㅠㅠ감사합니다 저 이 글 보고 에어비앤비 가격필터 기능 구현했습니다!!!! 너무너무 친절하게 잘 나와 있어서 큰 도움 받았습니다. 새해 복 많이 받으세요!!!!