• 로그인
  • 장바구니에 상품이 없습니다.

home2 게시판 React 게시판 클릭 시 기존 볼드처리 된 거 해제하고 다른거 볼드하려면..?

클릭 시 기존 볼드처리 된 거 해제하고 다른거 볼드하려면..?

2 글 보임 - 1 에서 2 까지 (총 2 중에서)
  • 글쓴이
  • #66214
    아래는 저기서 선택이 되었을 때 나오는 거
    
    
    
    두목님의 조언없이 혼자 해결해보려 했으나 
    이틀 동안 끙끙앓다가 도저히 안되겠다 싶어 질문남깁니다... 
    
    저기 저 레벨 중 하나를 선택하면 그거만 볼드 처리되게 하고
    기존에 볼드 처리가 되어있다면 (그러니까 이미 레벨을 선택해서 보고 있다면) 
    그 볼드처리 된 걸 빼고 가장 최근에 클릭한 레벨을 굵게 표시하고 싶습니다.
    
    지금 이미지에 있는 컴포넌트에서 난이도를 선택하면 형제 컴포넌트(?)에서 
    상위 카테고리와 난이도에 필터링된 정보만을 뱉어내고 있습니다.
    
    예를 들어 처음에 저 화면을 불러오면 http://localhost:3000/rank/에서 저 컴포넌트만 뜨게 되고
    4K의 Lv 18을 선택하면 사전에 설정된 Route와 useNavigate를 통해
    http://localhost:3000/rank/4k/18로 연결되고 있습니다. (맨 마지막 뒷 부분은 파라미터 문법으로 처리 중)
    (편의상 처음에 뜨는 컴포넌트를 A라고 하고 4k/18같은 거 눌렀을 때 나오는 컴포넌트를 B라고 할게여)
    
    그러면 저 B 컴포넌트에 클릭으로 접근하거나, 혹은 URL을 타이핑해서 직접 들어왔을 경우를 대비해
    B 컴포넌트가 마운트 되었을 때 현재 무슨 키(4k)와 난이도(18)인지를 state로 저장까지는 해놨습니다마는..
    
    지금 4k 18에 들어온 걸 어떻게 A컴포넌트로 보내 볼드처리 해주는 클래스 지정을 해주는 건 어떻게 하겠는데
    다른 걸 클릭했을 때에는 1. 기존에 붙었던 볼드 처리 클래스를 뗀다. 2. 클릭한 요소에다가 클래스를 부착한다.
    이렇게 해야 할 거 같습니다. 
    
    근데 대가리에 과부하가 와서 모 데키나이데스.....
    
    -----
    
    A 컴포넌트 
    
    
    
    
    
    import { useEffect, useState } from "react";
    import { useSelector } from "react-redux";
    import { useDispatch } from "react-redux";
    import { useNavigate } from "react-router-dom";
    import { setTitleView, setKeyAndDifficulty, setDescending, setClass } from "./../store.js"
    function RankOrderSelector(){
      let state = useSelector((state) => state)
      let dispatch = useDispatch()
      let navigate = useNavigate()
    
      function goToPage(key, difficulty){
        navigate(`/rank/${key}/${difficulty}`)
        dispatch(setKeyAndDifficulty({key: key, difficulty: difficulty}))
        /* 이제 해야 하는 거
        4k 18을 셀렉했다 가정
        그러면 4k에서 difficulty가 18인 위치의 index에 selected index를 true로 변환
        그러면 그에 해당하는 위치를 참조하는 클래스에 bold 붙어기
        그리고 다른 거 클릭하면 다시 selected를 원래대로 돌려서 초기화를 시키고
        다른 거 클릭한 곳에다가 bold를 붙이기.
        */ 
     }
      
      return (
        <div className="gradebox-wrapper-upper">
          <div className="gradebox-wrapper-inner">
            {/* 4~8키의 서열 난이도 표시하는 부분. */}
            {
              state.selectIndex.map((SinglekeyAndDifficulty, index)=>{
                return (
                  <div className="gradebox" key={index}>
                    <h1 className="key-name theme-pp">{SinglekeyAndDifficulty.key.toUpperCase()}</h1>
                      {
                      SinglekeyAndDifficulty.difficulty.map((singleDifficulty, index)=>{
                      return <span key={index} className={`link ${SinglekeyAndDifficulty.class[index]}`} onClick={()=>{
                        goToPage(SinglekeyAndDifficulty.key, singleDifficulty)
                      }}>Lv. {singleDifficulty}</span>
                      })
                    }
                  </div>
                )
              })
            }
          </div>
          <div className="option">
            <label className="switch">
              <input type="checkbox" onClick={(e)=>{
                dispatch(setTitleView(e.target.checked))
              }} defaultChecked></input>
              <span className="slider round"></span>
            </label>
            <span className="bold">곡 제목 표시</span>
            <label className="switch margin-left-1">
              <input type="checkbox" onClick={(e)=>{
                dispatch(setDescending(e.target.checked))
              }} defaultChecked></input>
              <span className="slider round"></span>
            </label>
            <span className="bold">
              내림차순
              </span>
          </div>
        </div>
      )
    }
    export default RankOrderSelector
    ---------------------------------------------------------- 
    B 컴포넌트
    
    
    
    import { useSelector, useDispatch } from "react-redux";
    import axios from 'axios'
    import { useEffect, useState } from 'react'
    import { useParams } from "react-router-dom";
    import { setKeyAndDifficulty } from './../store.js'
    // import Skeleton from 'react-loading-skeleton'
    // import 'react-loading-skeleton/dist/skeleton.css'
    function RankOrderList(props){
      // 컴포넌트 로드 시 선택된 키, 난이도에 해당하는 자료들을 서버에서 가져와 list 변수에 할당.
      let state = useSelector( (state) => state )
      let dispatch = useDispatch()
      let {selectedDifficulty} = useParams()
      let [list, setList] = useState([])
      var levelIndex = [[9,8],[7,6],[5,4],[3,2],[1,0]]
      // 이렇게 var을 써도 되는지 모르겠다 뭔가 var 쓰면 십색기가 되는 느낌
      /** RankOrderSelector에서 내림차순 On/Off시 참조할 Index를 변경함. */
      if (state.rankUserSelected.isDescending === true){
        var levelIndex = [[9,8],[7,6],[5,4],[3,2],[1,0]];
      } else {
        var levelIndex = [[1,0],[3,2],[5,4],[7,6],[9,8]];
      }
      // 컴포넌트가 처음 마운트되거나, store.js의 rankUserSelected(키, 난이도)가 업데이트 될 때 실행되는 함수.
      useEffect(()=>{
        /** Array 내용 중 선택한 difficulty 값에 해당하는 것만 반환해주는 함수 */
        function levelFilter(arr, difficulty){
          return arr.filter(el => el.level === difficulty)
        }
        /** 유저가 선택한 키 모드에 따라 AJAX 요청을 하기 위해 사용하는 함수 */
        function getUrl(key){
          return `http://ec2-3-34-144-236.ap-northeast-2.compute.amazonaws.com:54856/rank/list/${key}`
        }
        /** 유저가 RankOrderSelector에서 선택한 키 모드와 세부 난이도를 받아 서열 난이도 내림차순으로 걸러줌.*/
        switch(props.selectedKey) { 
          case '4K':
            axios.get(getUrl('FOUR'))
            .then((data)=>{
              let SelectedKeyFullSongList = data.data.data
              let filtered = levelFilter(SelectedKeyFullSongList, parseInt(selectedDifficulty)).sort(el => el.rank)
              setList(filtered)
            });
            break;
          case '5K':
            axios.get(getUrl('FIVE'))
            .then((data)=>{
              let SelectedKeyFullSongList = data.data.data
              let filtered = levelFilter(SelectedKeyFullSongList, parseInt(selectedDifficulty)).sort(el => el.rank)
              setList(filtered)
            })
            break;
          case '6K':
            axios.get(getUrl('SIX'))
            .then((data)=>{
              let SelectedKeyFullSongList = data.data.data
              let filtered = levelFilter(SelectedKeyFullSongList, parseInt(selectedDifficulty)).sort(el => el.rank)
              setList(filtered)
            })
            break;
          case '8K':
            axios.get(getUrl('EIGHT'))
            .then((data)=>{
              let SelectedKeyFullSongList = data.data.data
              let filtered = levelFilter(SelectedKeyFullSongList, parseInt(selectedDifficulty)).sort(el => el.rank)
              setList(filtered)
            })
            break; 
        }
        /** RankOrderSelector 컴포넌트에서 현재 선택한 키와 난이도가 선택될 때 store.js에 저장된 유저 선택값을 바꿔줌. */
        dispatch(setKeyAndDifficulty({key: props.selectedKey, difficulty: parseInt(selectedDifficulty)}))
      }, [state.rankUserSelected.selectedDifficulty, state.rankUserSelected.selectedKey])
      /** 서열 난이도의 단계를 받아 하 ~ 최상으로 반환해주는 함수 */
      function detailDifficultyFilter(detailDifficulty){
        switch(detailDifficulty){
          case 0:
          case 1:
            return '하';
          case 2:
          case 3:
            return '중하';
          case 4:
          case 5:
            return '중';
          case 6:
          case 7:
            return '중상';
          case 8:
          case 9:
            return '최상';
        }
      }
      return (
        <div className="flexbox" style={{'height':'10000px'}}>
          <h1 className="theme-pp header-margin header">{props.selectedKey}</h1>
          {/* Songs 클래스 네임 변경할것 */}
          <div className="songs">
          {/* 서열 9부터 0까지 내림차순으로 반환함 */}
          {
            levelIndex.map((detailDifficulty, index) => { 
              // 서열값이 있는지 확인하고 있으면 JSX 출력, 없으면 null 뱉기
              return list.filter(songlist => songlist.rank === detailDifficulty[0] || songlist.rank === detailDifficulty[1]).length !== 0
              ?  
                <div className="flexbox" key={index}>
                  <h1 className="marginX header-margin test-width">{selectedDifficulty}.<span className="order-nums">{detailDifficultyFilter(detailDifficulty[0])}</span></h1>
                  <div className='orderlist flexbox flex-wrap w100'>
                  {/* 특정 서열(ex:19.최상 → 19.9과 19.8)에 해당하는 곡명과 이미지들 전부 출력 */}
                  {
                    list.filter(songlist => songlist.rank === detailDifficulty[0] || songlist.rank === detailDifficulty[1]).map((el, index)=>{
                      return (
                        <div className="songlist" key={index}>
                          <div className="songbox">
                            <div className="imgbox">
                              < img src={process.env.PUBLIC_URL + '/music_disk/'+ el.name + '.webp'} alt={el.name}></img>
                              {/* 스켈레톤 UI를 넣고 싶은데 어떻게 해야 할 지 모르겠음 <Skeleton width={"120px"} height={"120px"} circle={true} /> */}
                              <div className="imgShadow"></div>
                              <span className={`level-badge ${el.difficulty}`}>{el.difficulty}</span>
                            </div>
                            {
                              state.rankUserSelected.songTitleView === true
                              ? <p className="song-title">{el.name} </p>
                              : null
                            }
                          </div>
                        </div>
                        )
                    })
                  }
                  </div>
                </div>
              : null
            })
          }
          </div>
        </div>
      )
    }
    export default RankOrderList
    
    
    
    
    -------------
    store.js
    
    
    
    import { createSlice, configureStore } from '@reduxjs/toolkit'
    let rankUserSelected = createSlice({
      name : "rankUserSelected",
      initialState : {selectedKey : "", selectedDifficulty : 0, songTitleView : true, isDescending : true},
      reducers : {
        setTitleView(state, action){
          state.songTitleView = action.payload
        },
        setDescending(state, action){
          state.isDescending = action.payload
        },
        setKeyAndDifficulty(state, action){
          state.selectedKey = action.payload.key;
          state.selectedDifficulty = action.payload.difficulty;
        },
      }
    })
    let selectIndex = createSlice({
      name : "selectIndex",
      initialState : [
        {key: '4k', difficulty : [19, 18, 17, 16], class: ["", "", "", ""]}, 
        {key: '5k', difficulty : [20, 19, 18, 17], class: ["", "", "", ""]}, 
        {key: '6k', difficulty : [20, 19, 18, 17], class: ["", "", "", ""]}, 
        {key: '8k', difficulty : [20, 19, 18, 17], class: ["", "", "", ""]}],
      reducers : {
        setClass(state, action){
          state.class = action.payload
        }
      }
    })
    export default configureStore({
      reducer: { 
        rankUserSelected : rankUserSelected.reducer,
        selectIndex : selectIndex.reducer
       }
    })
    export let { setTitleView, setKeyAndDifficulty, setDescending } = rankUserSelected.actions
    export let { setClass } = selectIndex.actions
    ----------------------
    App.js
    
    
    import 'bootstrap/dist/css/bootstrap.min.css';
    import './App.css';
    import { Routes, Route, useNavigate, Outlet } from "react-router-dom"
    import { Navbar, Container, Nav } from "react-bootstrap"
    import Main from "./routes/Main.js"
    import RankOrderSelector from './routes/RankOrderSelector';
    import RankOrderList from './routes/RankOrderList.js';
    import Footer from './routes/Footer.js'
    function App() {
      let navigate = useNavigate()
      return (
        
        <>
          {/* 네비게이션 영역 */}
          <Navbar bg="dark" variant="dark" className="z-index-10 pp-gradient pp-navbar-shadow">
            <Container>
              <Navbar.Brand href="#home" onClick={()=>{ navigate('/') }}>EZ2ARCHIVE</Navbar.Brand>
              <Nav className="me-auto">
                <Nav.Link href="#!" onClick={()=>{ navigate('')}} >성과표</Nav.Link>
                <Nav.Link href="#!" onClick={()=>{ navigate('/rank')}} >서열표</Nav.Link>
                <Nav.Link href="#!" onClick={()=>{ navigate('')}} >티어표</Nav.Link>
                <Nav.Link href="#!" onClick={()=>{ navigate('')}} >안내</Nav.Link>
              </Nav>
              <Nav>
                <Nav.Link href="#!" onClick={()=>{ navigate('')}} >로그인</Nav.Link>
              </Nav>
            </Container>
          </Navbar>
         
          <Container>
            {/* 라우트 영역 */}
            <Routes>
              <Route path="/" element={ <Main/> }></Route>
              <Route path="/rank" element={ <><RankOrderSelector/> <Outlet></Outlet></>}>
                <Route path="4K/:selectedDifficulty" element={ <><RankOrderList selectedKey="4K"/></> }></Route>
                <Route path="5K/:selectedDifficulty" element={ <><RankOrderList selectedKey="5K"/></> }></Route>
                <Route path="6K/:selectedDifficulty" element={ <><RankOrderList selectedKey="6K"/></> }></Route>
                <Route path="8K/:selectedDifficulty" element={ <><RankOrderList selectedKey="8K"/></> }></Route>
              </Route>
            </Routes>
            
            {/* 푸터 영역 */}
            <Footer/>
          </Container>
        </>
      );
    }
    export default App;
    
    
    
    
    		
    	
    #66232

    codingapple
    키 마스터
    lv18 글자엔 className={ state가 lv18이면 클래스명 붙여주고 아니면 떼주세요 }
    lv19 글자엔 className={ state가 lv19이면 클래스명 붙여주고 아니면 떼주세요 }
    ...
    계속 코드 짜면 됩니다
2 글 보임 - 1 에서 2 까지 (총 2 중에서)
  • 답변은 로그인 후 가능합니다.

About

현재 월 700명 신규수강중입니다.

  (09:00~20:00) 빠른 상담은 카톡 플러스친구 코딩애플 (링크)
  admin@codingapple.com
  이용약관, 개인정보처리방침
ⓒ Codingapple, 강의 예제, 영상 복제 금지
top

© Codingapple, All rights reserved. 슈퍼로켓 에듀케이션 / 서울특별시 강동구 고덕로 19길 30 / 사업자등록번호 : 212-26-14752 온라인 교육학원업 / 통신판매업신고번호 : 제 2017-서울강동-0002 호 / 개인정보관리자 : 박종흠