-
글쓴이글
-
2021년 8월 21일 19:30 #13835
김경원참가자안녕하십니까 강사님. 몇시간째 해매고 있어서 궁금한 점이 있어서 여쭙니다.
저는 최근 본 페이지를 <Show> 컴포넌트로 구현하기 위해서 props로 shoes state와 localStorage의 데이터를 arr이름으로 전송하였습니다.
궁금한 점
TypeError: Cannot read property 'map' of null -> 다음과 같은 에러가 계속 뜹니다. JSX 내에서 JS파일을 이용하여 반복문을 돌리기 위해서는 { } 중괄호 내부에 map 함수를 써서 반복문을 돌리라고 배웠는데 계속 다음과 같은 에러가 나서 답답합니다.
처음에는 최근 본 상품을 띄우기 위해서 Show 컴포넌트 내부의 map 반복문에서 <p> { props.shoes[value].title }</p> 과 같이 작성하였는데 title을 읽을수 없다는 둥... 계속해서 에러가 납니다. 혹시라도 map함수의 콜백함수 내부 인자인 value가 자료형이 String( Storage는 문자형이기 때매 ) 인가 싶어서 let Number = Number(value) 로 해결해보려했지만 이상한 에러만 계속 추가 되어서 여쭙습니다. 어떤게 잘못된 것인지 모르겠습니다.....[제가 만든 Show 컴포넌트]
function Show(props){
let history = useHistory();
console.log(props.shoes);
return (
<div className='show'>
<h3>최근 본 상품</h3>
{
props.arr.map((value)=>{
return (
<div className = 'show-product'>
<p onClick={
()=>{
history.push('/detail/${value}');
}
}>{value} 번째 상품</p>
</div>
)
})
}
</div>
)
}[Detail.js 에서 show 컴포넌트 부르기]
<Show shoes={props.shoes} arr={JSON.parse(localStorage.getItem('show'))}></Show>
[Detail.js 전체]
import React, { useContext, useEffect, useState } from 'react';
import { useHistory, useParams } from 'react-router-dom';
import styled from 'styled-components';
import './Detail.scss';
import { 재고Context } from './App.js';
import { Nav } from 'react-bootstrap';
import { CSSTransition } from 'react-transition-group';
import { connect } from 'react-redux';// 스타일 컴포넌트
let 박스 = styled.div'
width : 100%;';
let 제목 = styled.h4'padding-top : 8px;
font-size : 30px;
color : ${ props => props.색상 }
';// props : shoes, 재고, 재고변경()
function Detail(props){// 재고 Context 범위 내에 있기 때문에 useContext로 받아와서 사용
let 재고 = useContext(재고Context);
let [알림창, 알림창변경] = useState(true);
// 해당 Detail 컴포넌트가 렌더링 될때 실행되는 코드let [input, input변경] = useState();
let [누른탭, 누른탭변경] = useState(0);let [스위치, 스위치변경] = useState(false);
let { id } = useParams();
// params를 통해서 사용자가 detail/2라고 적었다면 2를 id 값으로 받아와서 데이터 바인딩 할수 있게끔 사용해주는 변수
// detail/2 접속시 => props.shies[id].price
// 하드코딩을 통한 데이터 바인딩이 아니라 유동적으로 user가 입력한 값을 받아와서 사용이 가능하다.
// {id, id2} 를 통해서 사용자가 입력한 값을 가져 올 수 있다.let history = useHistory();
// 방문 기록을 저장해 놓는 Object, goBack()을 통해서 뒤로가기 버튼 개발// 가격 정렬 이후에 영구적인 id와 user가 URL창에 입력한 id와의 비교를 통해 같은 페이지를 detail 페이지에 전송
let 찾은상품 = props.shoes.find((상품)=>{
return 상품.id == id;
});var arr;
useEffect(()=>{
let 타이머 = setTimeout(()=>{
//2초 후에 alert-box 사라지게
알림창변경(false);
},1000);arr = localStorage.getItem('show');
if (arr===null){
arr = [];
}else {
arr = JSON.parse(arr);
}
arr.push(id);
arr = new Set(arr); // 중복 제거
arr = [...arr];
console.log(arr);
localStorage.setItem('show', JSON.stringify(arr));
},[]);
// function 장바구니추가(추가상품){
// props.dispatch({type : '장바구니추가', payload : {추가상품 : '${추가상품}'}});
// }return (
<div className="container">
<박스>
<제목 className='my-detail'>Detail Page</제목>
</박스>{
알림창 === true
?<div className = 'my-alert'>
상품 재고 {props.재고[찾은상품.id]}개 남았습니다!
</div>
: null
}
<div className="row">
<div className="col-md-6">
<img src={'../이미지파일/shoes'+ (찾은상품.id+1) +'.jpg'} alt='dsa' width="100%" />
</div>
<div className="col-md-6 mt-4">
<h4 className="pt-5">{찾은상품.title}</h4>
<p>{찾은상품.content}</p>
<p>{찾은상품.price}</p>
<Info 재고={props.재고} 찾은상품={찾은상품}></Info>
<p>여기는 useContext를 사용한 재고 {재고[찾은상품.id]}</p>
<button className="btn btn-danger btn-layout" onClick = {()=>{
history.goBack();
}}>뒤로가기</button>
<button className="btn btn-danger btn-layout" onClick={()=>{
let tempArray = [...props.재고];
tempArray[찾은상품.id] = props.재고[찾은상품.id] - 1;
props.재고변경(tempArray);
props.dispatch({ type : '장바구니추가', payload : { id : '${props.state.length}', name : '${찾은상품.title}', quan : 1}})
history.push('/cart');
}}>주문하기</button>
</div>
</div><Show shoes={props.shoes} arr={JSON.parse(localStorage.getItem('show'))}></Show>
{/* Tab 기능 개발하기, 1번 누르면 1번에 대한 내용이 뜨게 개발한다. */}
<Nav className='mt-5' variant="tabs" defaultActiveKey="link-0">
<Nav.Item>
<Nav.Link eventKey="link-0" onClick = {()=>{ 스위치변경(false); 누른탭변경(0)}}>Option 0</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey="link-1" onClick = {()=>{ 스위치변경(false); 누른탭변경(1)}}>Option 1</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey="link-2" onClick = {()=>{ 스위치변경(false); 누른탭변경(2)}}>Option 2</Nav.Link>
</Nav.Item>
</Nav><CSSTransition in={스위치} classNames='wow' timeout={2000}>
<Tab 누른탭={누른탭} 스위치변경={스위치변경}></Tab>
</CSSTransition>
</div>
);
}function Show(props){
let history = useHistory();
console.log(props.shoes);
return (
<div className='show'>
<h3>최근 본 상품</h3>
{
props.arr.map((value)=>{
return (
<div className = 'show-product'>
<p onClick={
()=>{
history.push('/detail/${value}');
}
}>{value} 번째 상품</p>
</div>
)
})
}
</div>
)
}function Tab(props){
// 컴포넌트가 로드가 될때
useEffect(()=>{
props.스위치변경(true);
})if (props.누른탭 === 0){
return (
<div>0번째 탭 내용임 ㅅㄱ</div>
);
}else if(props.누른탭 === 1){
return (
<div>1번째 탭 내용임 ㅅㄱ</div>
);
}else if(props.누른탭 === 2){
return (
<div>2번째 탭 내용임 ㅅㄱ</div>
);
}
}function Info(props){
return (
<p>여기는 3중 props를 사용한 재고 : { props.재고[props.찾은상품.id] } </p>
);
}// store 에 저장되어 있는 state를 props화 시키는 작업
function state를props화(state){
return{
state : state.reducer,
alert초기값 : state.reducer2
}
}export default connect(state를props화)(Detail);
2021년 8월 21일 20:34 #13842
codingapple키 마스터Cannot read property 'map' of null 이건 map 함수 왼쪽에 있는 자료가 아무것도 없을 때 일어나는 에러입니다
arr 이걸 props로 잘 전송했는지 확인해야하고
로컬스토리지에 show라는 이름의 항목이 잘 있는지도 확인해야합니다 없으면 null이 남을걸요
2021년 9월 21일 00:49 #15344
김남용참가자<Show shoes={props.shoes}
arr={JSON.parse(localStorage.getItem('watched'))}>
</Show>이렇게 하니까 되는데요???
-
글쓴이글
- 답변은 로그인 후 가능합니다.