231224 TIL

thisisyjin·2023년 12월 28일
0

TIL 📝

목록 보기
106/113

CH 7. List Rendering

연습: 데이터 목록 렌더링하기

import React from 'react';

import Todo from './Todo';
import './styles.css';

const DUMMY_TODOS = [
    'Learn React',
    'Practice React',
    'Profit!'
];

// don't change the Component name "App"
export default function App() {
    return (
        <ul>
          Todo: Output todos
        </ul>
    );
}

“할 일 목록” 웹 앱을 만든다고 해봅시다. 여러분이 해야 할 작업은 더미 할 일 항목의 목록을 동적으로 출력하는 것입니다. 이 작업에 대해 Todo 컴포넌트가 준비되어 있지만, 할 일 텍스트를 수신하고 출력하기 위해서는 여전히 코드를 좀 더 추가해야 합니다.

더 정확히 말하면, App컴포넌트에서 제공된 DUMMY_TODOS 배열(변경해서는 안 됩니다!)을 JSX 요소 목록(정확히 말하면 <Todo> 요소)으로 변환해야 합니다. 모든 할 일 컴포넌트 항목은 text라는 prop을 통해 할 일 텍스트를 수신하고 출력해야 합니다.

내 코드 (PASS)

// App.js
import React from 'react';

import Todo from './Todo';
import './styles.css';

const DUMMY_TODOS = [
    'Learn React',
    'Practice React',
    'Profit!'
];

// don't change the Component name "App"
export default function App() {
    return (
        <ul>
          {DUMMY_TODOS.map((todo) => (<Todo text={todo}/>))}
        </ul>
    );
}

// Todo.js
import React from 'react';

export default function Todo({text}) {
    return <li>{text}</li>;
}

함수형 setState

  • 배열인 state를 업데이트할 때, 함수형 setState 사용
setUserList(prevState => ([...prevState, userData]);
  • 함수형 setState를 통해 prevState를 기본으로 사용할 수 있다.
  • 이렇게 하는 것이 직접 state를 setState 안에서 사용하는 것 보다 안전하다.

keys

  • list로 반환하는 경우 (map 메서드 사용 시)
  • 만약 array가 변경된 경우, 렌더링 성능 측면에서 Key가 필요. (warning message)
  • 새로운 아이템이 추가돤 경우 리액트에서는 아이템을 어떻게 정렬할지 알 수 없음. (다 비슷해보이기 때문)
    • 따라서 key를 지정해서 고유한 인덱스 역할을 할 수 있게 해줘야 함.
  • 만약 리스트에 고유 id값이 있다면 그것을 사용하고, 그렇지 않다면 index를 사용할 것. (권장 X)

[과제] 년도 필터링

  • 처음엔 state를 하나 추가하는 방법을 생각했지만, 굳이 state로 관리하지 않아도
  • 기존 state(productList)에서 filter 메서드만 해주면 되기 때문에 변수로 선언하여 props로 전달함.
const App = () => {
  const [productList, setProductList] = useState([]);
  const [filteredYear, setFilteredYear] = useState(2020); // default;

  const onChangeFilter = (selectedOption) => {
    setFilteredYear(selectedOption);
    filteredProductList(
  }
  
  const filteredProductList = productList.filter((product) => product.date.getFullYear().toString() === filteredYear);
  
  return (
    <YearFilter filteredYear={filteredYear} onChangeFilter={onChangeFilter} />
    <ProductList productList={filteredProductList} filteredYear={filteredYear}/>
  );
}
const YearFilter = ({filteredYear, onChangeFilter}) => {

  const handleChange = (e) => {
    onChangeFilter(e.target.value);
  }
  
  return (
    <select value={filteredYear} onChange={handleChange}>
			...
		</select>
  );
}
const ProductList = ({productList}) => {

  return (
    {
			productList.map((product) => (
				<div key={product.id}>
					<div>{product.title}</div>
					<div>{product.price}</div>
					<div>{product.date}</div>
		    </div>
			));
    }
  );
}

JSX 변수 저장

방법 1

  • JSX 코드가 복잡해질 수 있음.
const Component = () => {

...

return (
	  {filteredData.length === 0 && <p>No Data Found.</p>}
		{filteredData.length > 0 && filteredData.map((data) => (...))}
	)
}

방법 2

  • JSX를 let 변수로 저장해서 조건문으로 재할당 가능하게
  • 이 방법으로 작성 시 가독성 좋게 표현 가능하다. (취향대로 하면 OK)
const Component = () => {

...

let dataContent = <p>No Data Found.</p>;
if (filteredData.length > 0) {
  dataContent = filteredData.map((data) => (...));
}

return (
	  {dataContent}
	)
}

연습: 조건에 따라 콘텐츠 출력하기

사용자가 위험한 작업을 수행하려고 할 때 경고를 표시하는 웹 앱을 만들고 있다고 가정해 보겠습니다.

따라서, 여러분이 해야 할 작업은 사용자가 특정 버튼을 클릭하면 조건에 따라 경고 상자를 표시하는 것입니다. 경고 대화 상자 안에는 사용자가 경고를 해제(즉, 화면에서 경고 상자를 제거)할 수 있는 다른 버튼이 있습니다.

<button>을 클릭하지 않은 경우, 완성된 앱에는 이 UI가 표시되어야 합니다:

!https://img-b.udemycdn.com/redactor/raw/coding_exercise_instructions/2023-01-25_19-46-44-9e8772f6a8078c9d8f887588a31cdce2.png

버튼을 클릭한 경우에는 이 UI가 표시됩니다:

!https://img-b.udemycdn.com/redactor/raw/coding_exercise_instructions/2023-01-25_19-46-45-ea9890f0b7de91072bbb89b9cf4585bd.png

“진행” 버튼을 클릭하면 경고 상자가 다시 삭제되어야 합니다:

!https://img-b.udemycdn.com/redactor/raw/coding_exercise_instructions/2023-01-25_19-46-45-422a664c8ab05139df000f6945d859ff.png

이 작업에서는, 시작 코드에 있는 두 <button>요소의 클릭에 모두 반응해야 합니다. 두 번째 버튼은 id="alert"가 있는 <div> 외부에 <div id="alert">(및 모든 콘텐츠)를 표시해야 합니다.

내부의 버튼은 다시 숨겨야 합니다(즉, DOM에서 제거해야 합니다).

삼항 표현식을 사용할지, 조건에 따라 표시되는 JSX 코드를 변수에 저장할지는 사용자가 결정할 수 있습니다.

중요. Udemy 코드 편집기에서는 useState()를 쓰면 에러가 생길 수 있으므로 useState()가 아니라 React.useState()을 사용해야 합니다!

내 코드 (PASS)

import React from 'react';

// don't change the Component name "App"
export default function App() {
    const [isAlertOpen, SetIsAlertOpen] = React.useState(false);
    
    const openAlert = () => {
        SetIsAlertOpen(true);
    }
    const closeAlert = () => {
        SetIsAlertOpen(false);
    }
    return (
      <div>
      {
          isAlertOpen && ( 
          <div id="alert">
          <h2>Are you sure?</h2>
          <p>These changes can't be reverted!</p>
          <button onClick={closeAlert}>Proceed</button>
        </div>
        )
      }
        <button onClick={openAlert}>Delete</button>
      </div>    
    );
}

과제 - 조건부 컨텐츠

const dataPoints = [
	{
	  id: 1,
	  value: 293103,
	},
	{
	  id: 2,
	  value: 23525434,
	},
	{
	  id: 3,
	  value: 123232,
	},
	{
	  id: 4,
	  value: 999999999,
	}
];

const dataPointValues = dataPoints.map(dataPoint => dataPoint.value);
const maxValue = Math.max(...dataPointValues);

동적 스타일링

let barFillHeight = value / maxValue * 100 + '%';

...

<div style={{height: barFillHeight}}></div>
  • 나는 평소 styled-components에서 props로 넘겨줬었다.
  • 기본 style 어트리뷰트로도 가능하다.

연도별 데이터 월별로 정렬

const chartDataPoints = [
  {label: 'Jan', value: 0},
  {label: 'Feb', value: 0},
  {label: 'Mar', value: 0},
  {label: 'Apr', value: 0},
  {label: 'May', value: 0},
  {label: 'Jun', value: 0},
  {label: 'Jul', value: 0}
  {label: 'Aug', value: 0},
  {label: 'Sep', value: 0},
  {label: 'Oct', value: 0},
  {label: 'Nov', value: 0},
  {label: 'Dev', value: 0}  
];

// productDatas = [{date: ..., value: ... , ...}, {date: ..., value: ... , ...}, ... ]
for (const productData in productDatas) {
  const month = productData.date.getMonth();
  chartDataPoints[month].value += productData.value; // 합계
}

CH 8. React Styling

동적 인라인 스타일

const [isActive, setIsActive] = useState(false);

...
<div style={{color: isActive ? 'red' : 'black'}}></div>

연습: 동적 스타일

여러분이 해야 할 작업은 제공된 리액트 앱의 <p>Style me</p> 요소에 스타일(color: red)을 동적으로 적용하는 것입니다.

<button>이 처음 클릭될 때 스타일은 인라인 스타일(즉, style속성/prop을 통해) 적용되어야 합니다. 버튼을 다시 클릭하면, 스타일은 초기 스타일인 color: white로 다시 전환되어야 합니다.

버튼이 이 두 스타일 사이를 전환하는지 확인합니다(color: white <=> color: red).

버튼을 클릭하기 전, 완성된 앱의 모습은 다음과 같습니다:

!https://img-b.udemycdn.com/redactor/raw/coding_exercise_instructions/2023-01-25_20-03-23-02fdb3ce682409032876037dd28b863f.png

버튼을 클릭한 후의 모습은 다음과 같습니다:

!https://img-b.udemycdn.com/redactor/raw/coding_exercise_instructions/2023-01-25_20-03-24-7c8e4ce80ee28148c63cfe980f251d9d.png

버튼이 다시 클릭되었을 때의 모습은 다음과 같습니다:

!https://img-b.udemycdn.com/redactor/raw/coding_exercise_instructions/2023-01-25_20-03-24-eb267922d64394c0023ce989aa377ec2.png

내 코드 (PASS)

import React from 'react';

// don't change the Component name "App"
export default function App() {
    const [isToggle, setIsToggle] = React.useState(false);
    const handleClick = () => {
        setIsToggle(prev => !prev);
    }
    return (
        <div>
            <p style={{color: isToggle ? 'red' : 'white'}}>Style me!</p>
            <button onClick={handleClick}>Toggle style</button>
        </div>
    );
}

연습: 동적 CSS 클래스

여러분이 해야 할 작업은 제공된 리액트 앱의 <p>Style me</p> 요소에 CSS 클래스(active)를 동적으로 적용하는 것입니다. 이 작업은 이전 코딩 연습과 매우 유사하지만, 인라인 스타일이 아닌 CSS 클래스를 동적으로 설정합니다.

버튼을 처음 클릭할 때 스타일은 CSS 클래스로(즉, className속성/prop을 통해) 적용되어야 합니다. <button>을 다시 클릭하면 모든 CSS 클래스가 <p> 요소에서 제거되어야 합니다(이 상태도 초기 상태여야 합니다).

버튼이 이 두 가지 스타일 사이를 전환하는지 확인합니다(CSS 클래스 없음 <=> activeCSS 클래스).

버튼을 클릭하기 전의 완성된 앱의 모습은 다음과 같습니다:

!https://img-b.udemycdn.com/redactor/raw/coding_exercise_instructions/2023-01-25_20-18-40-a84ea52cbc1fe11c38ab9fec8263bfe4.png

버튼을 클릭한 후의 모습은 다음과 같습니다:

!https://img-b.udemycdn.com/redactor/raw/coding_exercise_instructions/2023-01-25_20-18-41-d38af590ee33c2badd29e3ec5e1f2965.png

버튼을 다시 클릭했을 때의 모습은 다음과 같습니다:

!https://img-b.udemycdn.com/redactor/raw/coding_exercise_instructions/2023-01-25_20-18-41-0a0b6c139e2be5bbb63d032e210309d1.png

내 코드 (PASS)

import React from 'react';

// don't change the Component name "App"
export default function App() {
    const [isActive, setIsActive] = React.useState(false)
    const handleClick = () => {
        setIsActive(prev => !prev);
    }
    return (
        <div>
            <p className={isActive && 'active'}>Style me!</p>
            <button onClick={handleClick}>Toggle style</button>
        </div>
    );
}

Styled-Components

  1. 동적 Props

const StyledButton = styled.button`
  color: ${props => props.active ? 'red' : 'black'}
`

<StyledButton active={isActive}>버튼</StyledButton>
  1. Media Query
const Button = styled.button`
  @media (min-width: 768px) {
    width: auto;
  }
`;
profile
기억은 한계가 있지만, 기록은 한계가 없다.

0개의 댓글