Skip to content

서치박스 & 셀렉박스 #7

@Ji-eun1

Description

@Ji-eun1

😎   결과

2022-08-31.7.38.16.mov


💭   내 생각

셀렉박스와 서치박스를 프론트로 구현하느냐, 백엔드로 구현하느냐에 많은 고민을 했다.
지금 생각하면 전체 게시물을 받아온 다음, 리덕스 store에 저장을 해두고
프론트에서 select value 나 search value 와 일치하는 리스트를 필터링하는 게 더 낫지 않나 싶다.



🔑   작업과정

프론트 - formList.tsx

1. 서치박스 및 셀렉박스 생성


const [searchValue, setSearchValue] = useState('');
const [selectValue, setSelectValue] = useState('latestOrder');

const onChangeSearch = (e: InputEventType) => onChangeText(e, setSearchValue, setSelectValue('latestOrder'));
const onChangeSelect = (e: SelectEventType) => onChangeText(e, setSelectValue, setSearchValue(''));

<Row className="g-2" style={{ marginBottom:50 }}>
    <Col md>
        <FloatingLabel 
            controlId="floatingInputGrid" 
            label="Search" 
        >
            <Form.Control 
                type="text" 
                placeholder="검색하세요" 
                value={ searchValue }
                onChange={ onChangeSearch }
            />
        </FloatingLabel>
    </Col>

    <Col md>
        <FloatingLabel controlId="floatingSelectGrid" label="Select">
            <Form.Select 
                aria-label="Select" 
                onChange={ onChangeSelect } 
                value={ selectValue }
            >
                <option value="latestOrder">최신순</option>
                <option value="viewOrder">조회순</option>
                <option value="heartOrder">인기순</option>
                <option value="whatIWrote" disabled={!signin}>내가 쓴 글</option>
                <option value="whatILike" disabled={!signin}>내가 좋아한 글</option>
            </Form.Select>
        </FloatingLabel>
    </Col>
</Row>


2. getForums

유저가 셀렉박스, 서치박스를 사용할 때마다 useEffect로 getForums 요청을 보낸다.


const getForums = () => {
    const body = {
        selectValue: selectValue,
        searchValue: searchValue,
        nickname: user.nickname
    }

    Forums.getForums(body)
    .then((data) => {
        console.log(data)
        setForums(data)
        dispatch(FORUM_POST(data))
        setActivePage(1);
    })
    .catch((err) => {
        console.log(err);
    })
}

useEffect(() => {
    getForums()
}, [selectValue, searchValue])


백엔드

3. routes > forums.js

프론트에서 getForums 요청을 보내면 백엔드는 getForums > getNewForums 순으로 동작하여 응답한다.


router.post('/get', getForums, getNewForums);


4. controller > forums.js

getForums - 유저정보와 하트를 조인하여 전체 게시물을 get
getNewForums - 셀렉박스 value 또는 서치박스 value 가 있을 경우, value 값과 일치하는 게시물만 걸러낸다.


const getForums = async (req, res, next) => {
    const selectValue = req.body.selectValue;
    const searchValue = req.body.searchValue;
    const nickname = req.body.nickname
    const user = await User.findOne({nickname:nickname})
    let userObjectId = '';

    if(user){
        const userId = user._id;
        userObjectId = ObjectId(userId)
    } 

    try{
        const forums = await Forum
        .aggregate([
            {
                $lookup: {
                    from: "users",
                    localField: "_user",
                    foreignField: "_id",
                    as: "_user",
                },
            },
            {  $unwind: "$_user" },
            {
                $lookup: {
                    from: "hearts",
                    localField: "_id",
                    foreignField: "_forum",
                    as: "_heart",
                    pipeline: [{
                        $match: { "_comment" : null }
                    }]
                },
            },
            { 
                $group: {
                    _id: "$_id",
                    forumId: { $first: "$_id" },
                    heartClickUsers: { $first: "$_heart._user" },
                    profileImagePath: { $first: "$_user.profileImagePath" },
                    nickname: { $first: "$_user.nickname" },
                    attachImageNames: { $first: "$attachImageNames" },
                    titleText: { $first: "$titleText" },
                    mainText: { $first: "$mainText" },
                    viewCount: { $first: "$viewCount" },
                    createdAt: { $first: "$createdAt" },
                }
            },
            { 
                $addFields: {
                    heartFill: { 
                        $cond: {
                            if: { $in: [ userObjectId, "$heartClickUsers"  ] }, 
                            then: true,
                            else: false,
                        }
                    },
                    heartCount: { $size: '$heartClickUsers' }
                } 
            },
            { 
                $project: { 
                    _id:0,
                    updatedAt:0,
                    __v: 0,
                    heartClickUsers:0,
                } 
            },
            {
                $sort: { createdAt: -1 }
            }
        ])
        
        req.forums = forums;
        req.user = user;

        if(selectValue || searchValue) {
            next()
        } else{
            res.status(200).json(forums);
        }
    } catch (err) {
        console.error(err);
        res.status(400).json({ msg: err });
    }
}

const getNewForums = async (req, res) => {
    const forums = req.forums;
    const selectValue = req.body.selectValue;
    const searchValue = req.body.searchValue;
    const user = req.user;

    if(searchValue) {
        const newForums = forums.filter(el => el.titleText.includes(searchValue))
        res.status(200).json(newForums);
    } else{
        if(selectValue === 'viewOrder'){
            const newForums = forums.sort((a, b) => b.viewCount - a.viewCount)
            res.status(200).json(newForums);
        } else if(selectValue === 'heartOrder'){
            const newForums = forums.sort((a, b) => b.heartCount - a.heartCount)
            res.status(200).json(newForums);
        } else if(selectValue === 'whatIWrote'){
            const newForums = forums.filter(el => el.nickname === user.nickname)
            res.status(200).json(newForums);
        } else if(selectValue === 'whatILike'){
            const newForums = forums.filter(el => el.heartFill === true)
            res.status(200).json(newForums);
        } else {
            res.status(200).json(forums);
        }
    } 
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions