관리 메뉴

프로그래밍 삽질 중

React로 필터 만들기(radioBox) - checkBox에서 사용한 filters 사용 본문

과거 프로그래밍 자료들/React

React로 필터 만들기(radioBox) - checkBox에서 사용한 filters 사용

평부 2022. 5. 23. 23:49
 

* '따라하며 배우는 노드, 리액트 시리즈 - 쇼핑몰 사이트 만들기' 강의 참고

* react -> node.js로 이미지 및 정보 저장하기

* mongoDB에 저장하는 것까지 확인

* 저장된 값의 정보 바꿔야함 -> 필터 적용시켜 찾기 위함

 

[1.필터 만들기 전 사전 작업]

 

1. MongoDB 수정

 

mongoDB price 항목 추가(int 타입)

[Server]

1. review/Data.js

 

const mongoose = require("mongoose");

const dataSchema = mongoose.Schema(
  {
    title: {
      type: String,
    },
    description: {
      type: String,
      maxlength: 50,
    },
    images: {
      type: Array,
      default: [],
    },
    seasons: {
      type: Number,
      default: 1,
    },
    price: {
      type: Number,
      default: 0,
    },

    //시간 자동 업데이트
  },
  { timestamps: true }
);

const Data = mongoose.model("Data", dataSchema);

module.exports = { Data };

 

 

[Client]

Review/DataUpload.js

 

import React, { useState } from "react";
import { Button, Form, Input } from "antd";
import axios from "axios";
import { useNavigate } from "react-router-dom";
import FileUpload from "./FileUpload";

const { TextArea } = Input;

const Seasons = [
  { key: 1, value: "봄" },
  { key: 2, value: "여름" },
  { key: 3, value: "가을" },
  { key: 4, value: "겨울" },
];

function DataUpload() {
  const [Title, setTitle] = useState("");
  const [Description, setDescription] = useState("");
  const [Images, setImages] = useState([]);
  //기본값 1로 둠
  const [Season, setSeason] = useState(1);
  const [Price, setPrice] = useState(0);

  const navigate = useNavigate();

  const titleChangeHandler = (event) => {
    setTitle(event.currentTarget.value);
  };

  const descriptionChangeHandler = (event) => {
    setDescription(event.currentTarget.value);
  };

  const seasonHandler = (event) => {
    setSeason(event.currentTarget.value);
  };

  const priceChangeHandler = (event) => {
    setPrice(event.currentTarget.value);
  };

  //추가1 : FileUpload의 값 받아오도록 함
  const updateImages = (newImages) => {
    setImages(newImages);
  };

  //추가2
  const submitHandler = (event) => {
    //페이지 자동 리프레시 되는 것 막음
    event.preventDefault();

    //값이 하나라도 비면 오류
    if (!Title || !Description || !Images || !Seasons || !Price) {
      return alert("모든 값을 작성해야 합니다.");
    }

    //값을 다 채우면 서버 request로 보낸다
    const body = {
      //로그인된 사람의 아이디
      title: Title,
      description: Description,
      images: Images,
      seasons: Season,
      price: Price,
    };

    console.log(Title, Description, Images);

    axios.post("/api/data", body).then((response) => {
      if (response.data.success) {
        alert("상품 업로드에 성공했습니다.");
        navigate("/review");
      } else {
        alert("상품 업로드에 실패했습니다.");
      }
    });
  };

  return (
    <div
      style={{
        display: "flex",
        justifyContent: "center",
        alignItems: "center",
        width: "100%",
        height: "100vh",
      }}
    >
      <div style={{ textAlign: "center", marginBottom: "2rem" }}>
        <br />
        <br />
        <br />
        <h2>계절 관련 업로드</h2>
        <Form onSubmitCapture={submitHandler}>
          {/* FileUpload에서 refreshFunction으로 제어 */}
          <FileUpload refreshFunction={updateImages} />
          <label>이름</label>
          <Input onChange={titleChangeHandler} value={Title} />
          <br />
          <br />
          <label>가격($)</label>
          <Input onChange={priceChangeHandler} value={Price} />
          <br />
          <br />
          <label>설명</label>
          <TextArea onChange={descriptionChangeHandler} value={Description} />
          <br />
          <br />
          <select onChange={seasonHandler}>
            {Seasons.map((city) => (
              <option key={city.key} value={city.key}>
                {city.value}
              </option>
            ))}
          </select>

          <br />
          <br />
          <div>
            <Button onClick={submitHandler}>확인</Button>
          </div>
        </Form>
      </div>
    </div>
  );
}

export default DataUpload;

 

 

* 결과

 

 

 

 

 

* ShowAllData.js에서 description={`$${data.description}`} -> description={`$${data.price}`}로 변경

 

 

[2.필터 만들기 설정하기]

 

[Client]

Sections/Datas.js & DataRadioBox.js

 

Datas.js

 

//Datas.js
const seasons = [
  { _id: 1, name: "봄" },
  { _id: 2, name: "여름" },
  { _id: 3, name: "가을" },
  { _id: 4, name: "겨울" },
];

const price = [
  {
    _id: 0,
    name: "모든 값",
    array: [],
  },
  {
    _id: 1,
    name: "$0 to $5",
    array: [0, 5],
  },
  {
    _id: 2,
    name: "$6 to $8",
    array: [6, 8],
  },
  {
    _id: 3,
    name: "$9 to $12",
    array: [9, 12],
  },
  {
    _id: 4,
    name: "more than $13",
    array: [13, 100],
  },
];

export { seasons, price };

 

 

DataRadioBox.js

 

import React, { useState } from "react";
import { Collapse, Radio } from "antd";

const { Panel } = Collapse;

function DataRadioBox(props) {
  const [Price, setPrice] = useState(0);

  const renderRadioBox = () =>
    props.list &&
    props.list.map((value) => (
      <Radio key={value._id} value={`${value._id}`}>
        {value.name}
      </Radio>
    ));

  //this.state.value -> Value로 제어(버튼 한 개만 눌러짐)
  const handleChange = (event) => {
    setPrice(event.target.value);
    props.boxFilters(event.target.value);
  };

  return (
    <div>
      <div>
        <Collapse
          style={{ height: "100%", width: "500px", marginLeft: "14.8%" }}
        >
          <Panel header="Prices" key="1">
            <Radio.Group onChange={handleChange} value={Price}>
              {renderRadioBox()}
            </Radio.Group>
          </Panel>
        </Collapse>
      </div>
    </div>
  );
}

export default DataRadioBox;

 

 

ShowAllData.js

 

import axios from "axios";
import React, { useEffect, useState } from "react";
import { Card, Row, Col } from "antd";

import DataCheckbox from "./Sections/DataCheckbox";
import DataRadioBox from "./Sections/DataRadioBox";

const { Meta } = Card;

function ShowAllData() {


 
  const boxFilters = (filters, category) => {
    const newFilters = { ...Filters };

    newFilters[category] = filters;
    // console.log("filters : ", filters);
    showFilters(newFilters);
    setFilters(newFilters);
  };

  //더보기 버튼과 방식 똑같음
  const showFilters = (filters) => {
    let body = {
      start: 0,
      end: End,
      filters: filters,
    };

    commonAxios(body);
    setStart(0);
  };

  return (
    <div style={{ width: "100%", margin: "0" }}>
      <br />
      <br />
      <br />
      <br />
      <h2 style={{ textAlign: "center" }}>DB에 저장한 거 확인하기</h2>

      <Row>
        {/* checkBox */}
        <Col lg={10} xs={20} style={{ position: "relative", left: "8.5%" }}>
          <DataCheckbox
            list={seasons}
            boxFilters={(filters) => boxFilters(filters, "seasons")}
          />
        </Col> //추가
        {/* radioBox */}
        <Col lg={10} xs={20} style={{ position: "relative", left: "2%" }}>
          {/* RadioBox */}
          <DataRadioBox
            list={price}
            boxFilters={(filters) => boxFilters(filters, "price")}
          />
        </Col>
      </Row>
      {/* card */}
      <div style={{ width: "85%", margin: "1rem auto" }}>
        <Row gutter={[20, 20]}>{renderCard}</Row>
      </div>

      {LimitImage >= End && (
        <div style={{ display: "flex", justifyContent: "center" }}>
          <button style={{}} onClick={showMoreData}>
            더 보기
          </button>
        </div>
      )}
    </div>
  );
}

export default ShowAllData;

 

 

* 결과(아직 필터 지정 x, 값이 보이지 않음)

 

 

[3.필터 적용하기]

 

 

[Client]

ShowAllData.js

 

import axios from "axios";
import React, { useEffect, useState } from "react";
import { Card, Row, Col } from "antd";
import ImageSlider from "./Sections/ImageSlider";

import { seasons, price } from "./Sections/Datas";
import DataCheckbox from "./Sections/DataCheckbox";
import DataRadioBox from "./Sections/DataRadioBox";

const { Meta } = Card;

function ShowAllData() {

  //필터 역할
  const [Filters, setFilters] = useState({ seasons: [], price: [] });

  useEffect(() => {
    let body = {
      start: Start,
      end: End,
    };

    commonAxios(body);
  }, []);

  //더 보기에 두 번 들어가기 때문에 따로 분리
  const commonAxios = (body) => {
    //post에 info값 넣을 것
    axios.post("/api/data/list", body).then((response) => {
      if (response.data.success) {
        // console.log(response.data);

        if (body.showMore) {
          setDatas([...Datas, ...response.data.dataInfo]);
        } else {
          setDatas(response.data.dataInfo);
        }
        setLimitImage(response.data.limitImage);
      } else {
        alert("상품을 가져오는데 실패했습니다.");
      }
    });
  };

  const boxFilters = (filters, category) => {
    const newFilters = { ...Filters };

    newFilters[category] = filters;
	
    //추가
    if (category === "price") {
      let priceValues = handlePrice(filters);
      newFilters[category] = priceValues;
    }

    showFilters(newFilters);
    setFilters(newFilters);
  };

  //더보기 버튼과 방식 똑같음
  const showFilters = (filters) => {
    let body = {
      start: 0,
      end: End,
      filters: filters,
    };

    commonAxios(body);
    setStart(0);
  };

//추가
  const handlePrice = (value) => {
    const data = price;
    let array = [];

    for (let key in data) {
      if (data[key]._id) {
        if (data[key]._id === parseInt(value, 10)) {
          array = data[key].array;
        }
      }
    }
    return array;
  };

  return (
    <div style={{ width: "100%", margin: "0" }}>
      <br />
      <br />
      <br />
      <br />
      <h2 style={{ textAlign: "center" }}>DB에 저장한 거 확인하기</h2>

      <Row>
        {/* checkBox */}
        <Col lg={10} xs={20} style={{ position: "relative", left: "8.5%" }}>
          <DataCheckbox
            list={seasons}
            boxFilters={(filters) => boxFilters(filters, "seasons")}
          />
        </Col>
        {/* radioBox */}
        <Col lg={10} xs={20} style={{ position: "relative", left: "2%" }}>
          {/* RadioBox */}
          <DataRadioBox
            list={price}
            boxFilters={(filters) => boxFilters(filters, "price")}
          />
        </Col>
      </Row>
      {/* card */}
      <div style={{ width: "85%", margin: "1rem auto" }}>
        <Row gutter={[20, 20]}>{renderCard}</Row>
      </div>

      {LimitImage >= End && (
        <div style={{ display: "flex", justifyContent: "center" }}>
          <button style={{}} onClick={showMoreData}>
            더 보기
          </button>
        </div>
      )}
    </div>
  );
}

export default ShowAllData;

 

 

[Server]

data.js

 

//DB에 저장한 정보 가져오기
router.post("/list", (req, res) => {
  //Start, End 제어
  let end = req.body.end ? parseInt(req.body.end) : 100;
  let start = req.body.start ? parseInt(req.body.start) : 0;

  let findData = {};

  for (let key in req.body.filters) {
    if (req.body.filters[key].length > 0) {
      // console.log("key", key);

      if (key === "price") {
        findData[key] = {
          //Datas의 price Array기준
          $gte: req.body.filters[key][0], //>= 크거나 같음
          $lte: req.body.filters[key][1], //<= 작거나 같음
        };
      } else {
        findData[key] = req.body.filters[key];
      }
    }
  }

  console.log(findData);

  Data.find(findData)
    .populate("title")
    .skip(start)
    .limit(end)
    .exec((err, dataInfo) => {
      if (err) return res.status(400).json({ success: false, err });
      return res
        .status(200)
        .json({ success: true, dataInfo, limitImage: dataInfo.length });
    });
});

 

* 결과