[JavaScript] 취향에 맞는 과일 추천해주기

Suvina·2024년 12월 24일

JavaScript

목록 보기
17/28

리액트로 만들고 싶었지만 머릿속 백지장 이슈로 자바스크립트로 먼저 제작하였다

function App() {

    const fruitArr = [
        {fruit: "딸기", producer: "국내산", season: "봄", calorie: 27},
        {fruit: "체리", producer: "수입산", season: "봄", calorie: 60},
        {fruit: "키위", producer: "수입산", season: "봄", calorie: 55},
        {fruit: "파인애플", producer: "수입산", season: "봄", calorie: 55},
        {fruit: "오렌지", producer: "국내산", season: "봄", 
        .
        .
        .
    ]


    let clickedArr = [];

    const checkHandler = (target) => {
        const checkbox = document.getElementsByName(target.name);

        // 체크 다중선택 방지
        for (let i = 0; i < checkbox.length; i++) {
            if (checkbox[i] !== target) {
                checkbox[i].checked = false;
            }
        }

        // 체크 변경 
        const index = clickedArr.findIndex(item => item.name === target.name);
        if (index > -1) {
            clickedArr[index].value = target.value;
        } else {
            clickedArr.push({name: target.name, value: target.value});
        }

        // 체크 해제 
        if (target.checked) {
            if (target.name === "calorie") {
                calorieFilter(target);
            }
        } else {
            if (index > -1) {
                clickedArr.splice(index, 1);
            }
        }

        // Q. 칼로리 부분을 함수로 정의하지 않고, 바로 필터값을 줄 수 있지 않을까?
        
        function calorieFilter() {
            let clickedCalorie;
            if (target.value === "0") {
                clickedCalorie = fruitArr.filter((fruit) => fruit.calorie < 40);
            } else if (target.value === "40") {
                clickedCalorie = fruitArr.filter((fruit) => fruit.calorie >= 40 && fruit.calorie < 60);
            } else if (target.value === "60") {
                clickedCalorie = fruitArr.filter((fruit) => fruit.calorie >= 60);
            }
            clickedArr = clickedArr.filter((item) => item.name !== "calorie");
            clickedArr.push({name: "calorie", value: target.value, fruits: clickedCalorie});
        }
        console.log(clickedArr);
    }

    // 결과 보여주기
    const resultFruit = () => {

        let filteredFruits = [...fruitArr];

        // Q. 굳이 if문으로 안해도 되지 않을까?
      
        clickedArr.forEach((condition) => {
            if (condition.name === "producer") {
                filteredFruits = filteredFruits.filter(
                    (fruit) => fruit.producer === condition.value
                );
            } else if (condition.name === "season") {
                filteredFruits = filteredFruits.filter((fruit) =>
                    fruit.season.includes(condition.value)
                );
            } else if (condition.name === "calorie") {
                // calorie 조건 필터링
                filteredFruits = filteredFruits.filter((fruit) =>
                    condition.fruits.some(
                        (calorieFruit) => calorieFruit.fruit === fruit.fruit
                    )
                );
            }
        });

        const resultDiv = document.getElementById("result");

        if (filteredFruits.length === 0) {
            resultDiv.innerHTML = `<p>다시 선택해주세요</p>`;
        } else {
            resultDiv.innerHTML = filteredFruits
            .map((fruit) => `<p>${fruit.fruit}</p>`)
            .join(""); //쉼표 제거
        }

    }

    return (
        <div className="App">
            <div className="wrap">
                <h6>1.국내산인가요, 수입산인가요?</h6>
                <label><input type="checkbox" name="producer" value="domestic" onChange={(e) => checkHandler(e.target)}/>국내산</label>
                <label><input type="checkbox" name="producer" value="imported" onChange={(e) => checkHandler(e.target)}/>수입산</label>
            </div>

            <div className="wrap">
                <h6>2. 계절은 언제인가요?</h6>
                <label><input type="checkbox" name="season" value="srping"
                              onChange={(e) => checkHandler(e.target)}/>봄</label>
                <label><input type="checkbox" name="season" value="summer"
                              onChange={(e) => checkHandler(e.target)}/>여름</label>
                <label><input type="checkbox" name="season" value="autumn"
                              onChange={(e) => checkHandler(e.target)}/>가을</label>
                <label><input type="checkbox" name="season" value="winter"
                              onChange={(e) => checkHandler(e.target)}/>겨울</label>
            </div>

            <div className="wrap">
                <h6>3. 칼로리는 얼마인가요?</h6>
                <label><input type="checkbox" name="calorie" value="0" onChange={(e) => checkHandler(e.target)}/>40
                                                                                                                 미만</label>
                <label><input type="checkbox" name="calorie" value="40" onChange={(e) => checkHandler(e.target)}/>40
                                                                                                                  이상~60 미만</label>
                <label><input type="checkbox" name="calorie" value="60" onChange={(e) => checkHandler(e.target)}/>60 이상</label>
            </div>
            <button onClick={resultFruit}>
                나에게 맞는 과일 보여주기
            </button>
            <div id="result"></div>

        </div>
    );
}

export default App;

Q. 칼로리 부분을 함수로 정의하지 않고, 바로 필터값을 줄 수 있지 않을까?

이전 코드

function calorieFilter() {
	let clickedCalorie;
	if (target.value === "0") {
		clickedCalorie = fruitArr.filter((fruit) => fruit.calorie < 40);
	} else if (target.value === "40") {
		clickedCalorie = fruitArr.filter((fruit) => fruit.calorie >= 40 && fruit.calorie < 60);
	} else if (target.value === "60") {
		clickedCalorie = fruitArr.filter((fruit) => fruit.calorie >= 60);
	}
	clickedArr = clickedArr.filter((item) => item.name !== "calorie");
	clickedArr.push({name: "calorie", value: target.value, fruits:clickedCalorie});
}

개선 코드

if (target.name === "calorie") {
	let clickedCalorie;
	if (target.value === "0") {
		clickedCalorie = fruitArr.filter((fruit) => fruit.calorie < 40);
	} else if (target.value === "40") {
		clickedCalorie = fruitArr.filter((fruit) => fruit.calorie >= 40 && fruit.calorie < 60);
	} else if (target.value === "60") {
		clickedCalorie = fruitArr.filter((fruit) => fruit.calorie >= 60);
	}
	clickedArr = clickedArr.filter((item) => item.name !== "calorie");
	clickedArr.push({name: "calorie", value: target.value, fruits:clickedCalorie});
}

=> 함수로 정의하지 않고, target.name === "calorie" 일 때만 실행 가능한 구문으로 변경하였다.


Q. 굳이 if문으로 안해도 되지 않을까?

이전 코드

clickedArr.forEach((condition) => {
	if (condition.name === "producer") {
		filteredFruits = filteredFruits.filter((fruit) => fruit.producer === condition.value;
	} else if (condition.name === "season") {
		filteredFruits = filteredFruits.filter((fruit) => fruit.season.includes(condition.value));
	} else if (condition.name === "calorie") {
		filteredFruits = filteredFruits.filter((fruit) => condition.fruits.some((calorieFruit) => calorieFruit.fruit === fruit.fruit));
	}
});

개선 코드

const filterFunctions = {
	producer: (fruits, condition) =>
		fruits.filter((fruit) => fruit.producer === condition.value),
	season: (fruits, condition) =>
		fruits.filter((fruit) => fruit.season.includes(condition.value)),
	calorie: (fruits, condition) =>
		fruits.filter((fruit) => condition.fruits.some((calorieFruit) => calorieFruit.fruit === fruit.fruit)                
	),
};

clickedArr.forEach((condition) => {
	const filterFunction = filterFunctions[condition.name];
	if (filterFunction) {
		filteredFruits = filterFunction(filteredFruits, condition);
	}
});

=> producer, season, calorie를 기준으로 데이터를 필터링하는 함수를 만들고, 체크된 답지 리스트인 clickedArr를 해당 필터 함수로 필터링한다.

다음은 리액트로 리팩토링하기

profile
개인공부

0개의 댓글