[FE] React-NodeBird 리뉴얼 정리(3)

N·2023년 2월 21일
0

react-nodebird-front

목록 보기
5/8

redux에 대해서

  • redux 사용하는 이유
    -로그인한 사용자의 정보와 같이 여러 컴포넌트에서 공통적으로 사용되는 데이터들이 있는데 이런 데이터를 흩어지지 않게 하고 싶으면 부모컴포넌트를 두어서 자식 컴포너트로 각각 보내줘야 되는데 이 과정이 매우 귀찮기 때문에 중앙에서 하나로 관리를 해서 뿌려주는 중앙 데이터 저장소로 사용
  • 컨텍스트 API도 그 역할을 한다. 이런 역할을 하는 도구로써 대표적인 4가지가 있다. 컨텍스트 API, redux, 아폴로, mobx

어떻게 골라야 되나?

  • redux의 장점: 원리가 간단해서 에러가 잘 생기지 않고 에러가 발생해도 추적하기 쉽다. 따라서 앱이 안정적이 된다.

  • redux의 단점: 코드량이 많다 -> next-redux-wrapper를 쓰면 편하다

  • mobx의 장점: 코드량이 적고 생산성이 높아진다

  • mobx의 단점: 에러 발생시 추적(트래킹)이 어렵다

  • 컨텍스트 API는 비동기를 지원하기 쉽지 않다는 단점, 요청 성공 실패 3가지를 다 직접 구현해줘야 한다.

  • 예를 들면 아래와 같은 코드가 컴포넌트에 많이 들어가게 된다.

axios.get('/data')
.then(()=>{setData()})
.catch(()=>{serError(error)})
  • 화면을 비즈니스 로직(데이터 요청)과 분리하는게 컴포넌트의 역할(화면을 그리는 것)에 더 적절하다? -> 컨텍스트 API로 구현하다보면 결국엔 redux나 mobx처럼 구현을 하게 된다 -> 처음부터 전역상태관리 라이브러리를 사용하자!

  • 앱이 커지면 중앙 저장소도 커지므로 redux에서 reducer를 여러개로 쪼개면 중앙 저장소가 커지는 것을 어느정도 방지할 수 있다

redux의 원리

  1. 액션에 바꾸고 싶은 데이터를 담는다

  2. dispatch로 저장소에 보낸다

  3. reducer로 액션에 따른 데이터 변동사항을 저장소(state)에 반영한다 -> 액션을 하나 만들때마다 리듀서도 하나씩 만들어야 한다(state+reducer = store)

    //action
    {
    	type: 'CHANG_NICKNAME',
        data: 'boogiecho'
    }
    
    //reducer
    switch (action.type) //type은 액션객체의 이름
      case 'CHANGE_NICKNAME':
        return {
        	...state,
              name: action.data
        }
    case 'CHANG_AGE':
    	return {
    		...state,
    	  age: action.data
    	}
    
  • return {...state, age: action.data} 이렇게 하는 이유는 불변성때문? -> 새로운 객체를 만들어줘야(return) 데이터 변동이 추적 가능하기 때문이다. 개발모드는 데이터를 계속 보유하고 있지만 프로덕션모드(?)는 데이터를 버린다?(이해X)

  • 객체안에 있는 데이터를 전부 새롭게 만들어 주지 않는 이유(...state)는 참조관계를 유지해야 하는 것들은 유지하도록 놔두는게 메모리를 많이 잡아먹지 않기 때문이다(비구조화 할당)

  • 자바스크립트에서 불변성이란? 참조자료형의 경우 객체를 할당하면 두개의 변수가 같은 객체를 가리키므로 비교했을때 항상 true가 나오는 것
    {} === {} : false
    const a = {}
    b = a
    a === b : true

사용방법

  • 설치 npm i next-redux-wrapper@6.0.2 -> 6버전으로 사용해야된다(현재 자동설치하면 8버전이 설치되므로 버전을 낮춰줬다)
  • 최상단에 store 폴더 만들어주기
import { createWrapper } from "next-redux-wrapper";

const configureStore = () => {};

const wrapper = createWrapper(configureStore, {
    debug: process.env.NODE_ENV === "development",
});

export default wrapper;


//2번째 전달인자는 옵션객체인데 옵션객체가 true면 redux에 관해서 좀 더 자세한 설명이 나온다 -> 코딩할 때 편하므로 꼭 넣어주세요
  • _app.js의 export 부분을 감싸기
export default wrapper.withRedux(NodeBird);
  • redux wrapper 6버전이 나오기 전에는 provider로 store를 전역에 뿌려줬었지만 6버전(지금 사용하는 버전)부터는 next redux wrapper가 provider를 자동으로 적용해주기 때문에 추가하면 오히려 문제가 발생한다.

실제로 구현하기

주의할 점

  • 불변성을 지키면서 만들어야 히스토리가 남는다.
  • 불변성이란 객체가 생성된 이후 값이 변하지 않는 것
  • 불변성을 유지하는 값 : boolean, number, string, null, undefined, symbol
  • 불변성을 유지하지 않는 값 : object, array(엄격하게 말해서 object?)
  • 참고블로그 : https://velog.io/@co_mong/JS-%EB%B6%88%EB%B3%80%EC%84%B1Immutability

발생했던 에러

  • Can't resolve '@ant-design' in'C:\Users...' -> 설치되지 않았다는 뜻, import에 오타가 있는지 확인
  • text가 object, object로 뜨면 문자열이 object로 바뀌고 있다는 뜻
  • 원인 : setState자리에 set으로 시작하는 함수를 넣지 않아서 발생
  • 해결방법 : const [text, setText] = useState("");로 수정
  • antd 최신 버전을 쓰면 발생하는 오류
    - transform 안에 position fixed를 사용하면 브라우저가 position fixed를 제대로 잡지 못하는 버그가 발생한다.
    - antd 최신버전에 transform이 추가되어서 발생(ant-card-cover부분)
    - transform을 해제하는 방법 -> Global style에서 해제
export const Global = createGlobalStyle `
	.ant-card-cover {
		transform: none !important;
	}

Ref

  • 실제 돔에 접근하기 위해서 사용
  • 이미지 업로드 파일창 클릭할 때 사용할 수 있다
    const imageInput = useRef();
	const onCLickImageUpload = useCallback(() => {
        imageInput.current.click();
    }, [imageInput.current]);
  	<div>
    	 <input type="file" multiple hidden ref={imageInput} />
   	     <Button onClick={onCLickImageUpload}>이미지 업로드</Button>
         <Button
                    type="primary"
                    style={{ float: "right" }}
                    htmlType="submit"
         > 
          짹짹
		 </Button>
    </div>

JSX와 KEY

  • 배열 안에 JSX를 넣을 때는 Key를 꼭 넣어줘야 한다.
  • key에 index를 넣는 것은 안티패턴(하지 말아야 하는 방법)이다. 왜냐면 중간에 있는 데이터가 수정, 삭제될 때 원하는 값이 정확하게 바뀌지 않기 때문
<Card
    cover={post.Images[0] && <PostImages images={post.Images} />}
    actions={[
    <RetweetOutlined key="retweet" />,
    <HeartOutlined key="heart" />,
    <MessageOutlined key="comment" />,
    <Popover
        key="more"
        content={
         <Button.Group>
            {me.id && post.User.id === me.id ? (
                <>
                  <Button>수정</Button>
                  <Button type="danger">삭제</Button>
                </>
                ) : (
                  <Button>신고</Button>
                )}
                  </Button.Group>
              }
      >
      <EllipsisOutlined key="ellipsis" />
   </Popover>,
 ]}
>

옵셔널 체이닝 연산자

  • const me && me.id -> const id = me?.id me.id가 있으면 바꿔주고 없으면 undefined로 바꿔주는 연산자, id값이 있나없나를 체크후 있을때 값을 넣어준다

img 태그의 alt, role

  • 이미지에 대한 설명, 시각장애인에게 힌드를 주는 속성이다
  • react-hook-form에서 alt를 넣지 않으니까 이미지가 업로드 되지 않았던 기억이 있는데 별도로 설정을 해준거였는지 생각이 나지 않는다..
  • 페이스북은 alt를 넣는 AI를 별도로 사용한다고 한다
  • <img role="presentation" onClick={onZoom}/> 는 스크린 리더가 onClick안에 있는 내용은 굳이 클릭할 필요가 없다는 의미를 담고있다. button이나 input이 아닌 애들은 role="presentation"을 넣어주자.

정규표현식 사용하기

  • https://regexr.com/ 에 가면 확인해 볼 수 있다
  • /g : 여러개 찾을 때 붙인다
  • /#./ : #뒤에 있는 점의 개수만큼 글자를 선택한다
  • /#.+/ : #뒤에 연결된 글자를 모두 선택한다(공백까지 포함)
  • /#[]/ : 공백을 포함하지 않고 #의 바로 뒤에 있는 단어 안에서 대괄호 안에 있는 글자를 선택한다
  • #[^] : ^뒤에 있는 글자를 제외하고 #뒤에 있는 글자 하나를 선택한다
  • #[^]+ : ^뒤에 있는 글자를 제외하고 #뒤에 있는 글자 모두를 선택한다(공백포함)
  • #[^\s] : \s는 공백을 의미
  • /#[^\s#]+/g : 뒤에 붙은 #를 제거한다

최종

const PostCardContent = ({ postData }) => {
//split은 특이하게 정규표현식 내부를 소괄호로 감싸야한다
  return (
      <div>
          {postData.split(/(#[^\s#]+)/g)}
      </div>
  );
};

profile
web

0개의 댓글