728x90

useCallback특정 함수를 렌더링할 때마다 새로 만들지 않고, 재사용하기 위해 사용하는 Hook이다. 

 

아래 코드에는 useCallback이 사용된 change와 insert라는 함수가 있다.

change의존성 배열이 빈 배열이고, insert의존성배열에 string과 stringList가 들어가 있다. 

 

const change = useCallback((e) => {
	setString(e.target.value); 
}, []); 

const insert = useCallback((e) => {
	const newList = stringList.slice(); 
    	newList.push(string); 
    	setStringList(newList); 
}, [string, stringList]); 

 

둘의 차이가 무엇이길래, 하나는 의존성 배열이 비어있고, 하나는 값이 포함되어 있을까?

 

change는 두번째 인자에 빈 배열을 주었기 때문에, 최초 렌더링 시에만 함수가 생성되고 이후에는 생성되지 않는다. 

 

insertstring과 stringList가 변경될 때만 함수를 재생성한다. 

 

즉, insert의 경우 string과 stringList가 변하면 함수도 재생성되어야 한다. 즉, 두 state에 의존적이다.

하지만, change는 state를 사용하지 않고, 단지 state를 변경하는 것이므로, state에 의존적이지 않다.

state가 변함에 따라 change 함수를 재생성해줄 필요는 없는 것이다.

 

정리하자면, 해당 함수에서 state를 사용한다면, 말그대로 state에 의존하는 함수이므로 두번째 인자의 배열 안에 state를 추가해줘야 하고,

state에 의존적이지 않은 함수라면 빈 배열로 넣어주면 된다.   

 

 

 

 

728x90
728x90

antd form을 사용할 때, 특정 input의 값을 reset하고 싶을 때가 있다. 

 

예를 들어, 아래와 같이 'password'라는 name을 가진 Input을 reset 시키고 싶다면, 

 

        <Form.Item
          name="password"
          label="비밀번호"
          rules={[
            {
              required: true,
              message: '비밀번호를 입력해주세요!',
            },
          ]}
          hasFeedback
        >
          <Input.Password placeholder="비밀번호를 입력해주세요" />
        </Form.Item>

 

다음과 같이 form.setFieldsValue 안에서 password(Form.Item의 name) : ''로 바꿔주면 된다.  

 

form.setFieldsValue({
      password: '',
});
728x90
728x90

activefocususer의 action에 따라 스타일링의 변화를 주고 싶을 때 사용하는 선택자(User Action Pseudo-classes)이다. 

 

둘은 비슷해보이지만, 차이가 있다. 

 

focus는 (input을 눌러) focusing이 되었을 때, background-color를 변하게 하고 싶으면 사용한다. 

 

 

active는 (input을) 누르는 찰나에 background-color를 변하게 하고 싶을 때 사용하면 된다. 

 

728x90
728x90

a 클릭 영역 늘리기

a(anchor)의 기본 display는 inline이다. 그래서 부모의 영역이 넓더라도(예를 들어, 부모의 width가 500px이라고 하자), a태그의 width가 200px이라면, 클릭할 수 있는 영역의 width는 200px 밖에 되지 않는다. 

 

하지만, anchor의 클릭 영역이 작으면 클릭하기가 불편하기 때문에, anchor가 부모의 영역만큼 차지하게 해주는 것이 좋다. 

 

block은 width 값을 따로 부여하지 않을 경우, 부모의 100%만큼 width가 설정된다. (inline-block은 아님)

 

그래서, 다음과 같이 anchor의 display를 block으로 바꾸어주면, a의 클릭 영역을 늘릴 수 있다. 

 

a {
  display: block;
}

 

next에서 router.push()와 Link의 차이 

결론부터 말하자면, SEO(검색엔진최적화)가 중요하다면 Link를 사용하는 게 좋다

 

Link를 사용함으로써, 전체 페이지가 reload 되어 overriden(SSR)된다. 즉, Link를 사용했을 때 검색엔진의 크롤러는 Link가 다른 페이지로 이동하기 위함을 알 수 있고 검색엔진 최적화에 좋다

 

router.push는 주로 이벤트 핸들러(ex. onClick)에서 사용된다고 한다. 그렇지만 단지 다른 페이지로 이동하기 위해서는 사용하지 않는 게 좋다.

 

즉, Link의 기능만으로 부족해서 router의 특정 기능이 필요한 게 아니라면 Link를 사용하는 게 좋다. 

 

참고링크) https://stackoverflow.com/questions/65086108/next-js-link-vs-router-push-vs-a-tag?openLinerExtension=true

 

 

 

 

 

   

728x90
728x90

axios.defaults.baseURL

axios 요청을 보낼 때 아래처럼 url을 적어주어야 한다. 그런데 'http://localhost:3065' 부분은 공통이라 계속 적어주어야 한다. 나중에 배포를 하게 되어 url이 바뀌게 되면, 모든 url 부분을 다 바꿔줘야 하는데 굉장히 귀찮은 일이다. 

 

function loginAPI(data) {
  return axios.post('http://localhost:3065/user/login', data);
}

function logoutAPI() {
  return axios.post('http://localhost:3065/user/logout');
}

function signUpAPI(data) {
  return axios.post('http://localhost:3065/user', data);
}

 

이럴 때, axios.defaults를 사용한다. 'axios.defaults'를 통해 모든 요청에 적용될 구성 기본 값을 지정할 수 있다.

 

axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

 

나의 경우는 redux-saga를 사용했기 때문에 saga 폴더의 index.js 파일에서 baseURL을 지정해주었다. 이렇게 해주면, 나중에 배포 후에 baseURL이 변하더라도 이 부분만 변경해주면 된다.

 

axios.defaults.baseURL = 'http://localhost:3065';

 

findOne

로그인한 유저를 db에서 꺼내오고 싶을 때, findOne을 사용해준다. findOne테이블의 데이터를 하나만 가져온다는 뜻이다. 

 

const user = await User.findOne({ where: { id } });
728x90
728x90

table width 고정, 자동 줄바꿈

table에서 width를 따로 설정했음에도 불구하고, 컨텐츠의 내용이 길어지니 아래와 같이 width가 계속해서 늘어났다

 

 

 

이를 방지하기 위해서는 테이블의 사이즈에 맞게, 컨텐츠가 알아서 자동 줄바꿈을 해야한다. 

 

word-break: break-all; 속성을 사용하면 아래와 같이 알아서 줄바꿈을 할 수 있다. 

 

table > tr > td{
    word-break: break-all;
}

 

 

 

word-break텍스트가 자신의 content-box 밖으로 overflow할 때 줄을 어떻게 바꿀지 정해주는 속성이다. 

728x90
728x90

*하루동안 새롭게 알게된 부분, 에러를 해결한 방법 등을 작성하는 개발일기입니다. 다른 사람에게도 설명해줄 수 있도록 제 머릿속에 넣기 위해 정리를 시작하게 되었습니다. 

React 버튼 클릭 효과 유지하기

페이지 버튼이든 카테고리 버튼이든, 아래처럼 버튼을 클릭했을 때 style을 유지하고 싶은 경우가 있다.

 

 

 

클릭 효과를 유지하기 위한 방법은 여러가지가 있겠지만, 나는 클릭 이벤트 리스너를 붙여 classList를 추가해주고 지우는 방식을 택했다.  

 

// 각 페이지 버튼마다 'pages'라는 클래스를 가지고 있다. 
const pages = document.getElementsByClassName('pages');  
    
const clickHandler = (e) => {
    // 처음 로딩되었을 때는 1번 페이지에 선택되어 있어야 하기 때문에, 
    // 1번 페이지 버튼은 'first-page' 클래스를 가지고 있다. 
    // 만약, 클릭된 클래스 리스트에 first-page가 없다면 첫번째 페이지는 
    // 계속 선택되어 있을 필요가 없기 때문에 remove 해준다. 
    if (!e.target.classList.contains("first-page")) {
        pages[1].classList.remove("first-page");
    }
    
	// 모든 페이지 버튼에서 활성 클래스인 'active-page'를 지워 초기화 해준다. 
    for (var i = 0; i < pages.length; i++) {
        pages[i].classList.remove("active-page");
    }
    // 현재 클릭된 버튼에만 활성 클래스인 'active-page'를 붙여준다. 
    e.target.classList.add("active-page");
}

// 모든 pages 클래스를 가진 요소에 클릭 이벤트 리스너를 붙여주었다. 
// 그래서 클릭 이벤트가 발생하면, clickHandler 함수가 실행된다. 
const init= () => {
    for (let i = 0; i < pages.length; i++) {
      pages[i].addEventListener("click", clickHandler);
    }
}

init();

 

 

  • addEventListener - 특정 이벤트가 발생했을 때 특정 함수를 실행할 수 있게 해주는 기능. 여기서는 click 이벤트가 발생했을 때 clickHandler 함수를 실행해준다. 
  • document.getElementsByClassName(className) - HTML에서 있는 요소 중, 주어진 클래스명을 가진 모든 요소들을 배열에 담아 리턴해준다. 
  • e.target - 이벤트 객체의 타깃, 예를 들어, 2번 페이지를 눌렀다면 <li class="pages active-page" style="user-select: auto;">2</li>가 리턴된다. 
728x90
728x90

*하루동안 새롭게 알게된 부분, 에러를 해결한 방법 등을 작성하는 개발일기입니다. 다른 사람에게도 설명해줄 수 있도록 제 머릿속에 넣기 위해 정리를 시작하게 되었습니다. 

React 게시판 최신순으로 정렬

아래와 같이 게시글들이 최신순으로 정렬되기 바란다면 어떻게 해야할까? 

 

 

 

서버에서 그대로 데이터를 받아온 뒤, 컴포넌트에서 reverse를 하려고 하면 리렌더링될때마다 reverse 될 수있다

 

그래서 Load User action에 성공한 뒤, data를 Users에 담을 때 아예 reverse()를 하여 담으면 된다. 

 

728x90
728x90

*하루동안 새롭게 알게된 부분, 에러를 해결한 방법 등을 작성하는 개발일기입니다. 다른 사람에게도 설명해줄 수 있도록 제 머릿속에 넣기 위해 정리를 시작하게 되었습니다. 

React에서 map 사용 시 key를 설정해줘야 하는 이유는

아래와 같이 컴포넌트를 반복하여 렌더링해줘야 하는 경우, map을 사용한다. 

 

 

 

그런데 이 때, 배열 내부의 엘리먼트에 key 값을 지정해주지 않으면, 'Each child in a list should have a unique key prop.' 경고문이 뜨게 된다. 

 

 

리액트 공식문서에서는, key어떤 아이템이 변화되거나 추가 또는 삭제되었는지를 알아차리기 위해 필요하다고 한다. 

 

리액트는 state에서 변경된 부분만 찾아 리렌더링해주는데, 이때 가상 dom과 비교하여 바뀐 부분만 리렌더링해준다. 만약, 배열에 요소가 추가되었다면 배열 전체가 변경된 것이라고 생각하고 전체를 리렌더링 하게 된다. 마지막 요소만 변경되었으니, 전체를 리렌더링할 필요는 없는데도 말이다. 

 

그래서 배열 내부 엘리먼트에 key를 지정해줘야 한다. key 값을 지정해주면 리액트는 배열에 추가된 요소에 대해서만 리렌더링한다. 즉, key는 배열의 어떤 원소에 변동이 있었는지 알아내고자 할 때 사용되는 것이다. 따라서, 데이터가 가진 고유의 값을 key로 설정해야 한다. 

 

const PostList = ({ posts }) => {
    return(
        posts.map((post) => {
            return(
                <tr key={post.id}>
                    <td>{post.id}</td>
                    <td>{post.nickname}</td>
                    <td>{post.role}</td>
                    <td>{post.phone}</td>
                </tr>
            );
        })
    ); 
}

export default PostList; 

 

 

key 값으로 index를 설정하는 경우도 있는데, 어떤 경우에는 key 설정의 장점을 하나도 살리지 못하고 배열 전체가 리렌더링 될 수 있다.  배열에 첫 번째 위치에 새로운 element를 넣게 되면, 기존 배열의 index가 하나씩 밀리게 된다. 그럼 결국, 배열 전체가 변경되었다고 생각하기 때문에 배열 전체가 리렌더링 되는 것이다. 

 

// 기존 배열 
key 0, {id: 0, title: 'hello', content: 'olleh'}, 
key 1, {id: 1, title: 'my', content: 'ym'}, 
key 2, {id: 2, title: 'name', content: 'eman'}, 

// 배열 첫 번째 위치에 새로 element를 넣음 
key 0, {id: 3, title: 'is', content: 'si'}, 
key 1, {id: 0, title: 'hello', content: 'olleh'}, 
key 2, {id: 1, title: 'my', content: 'ym'}, 
key 3, {id: 2, title: 'name', content: 'eman'}, 

 

그래서, element를 고유하게 식별할 수 있는 unique한 값을 key로 설정해주는 게 좋다. 가장 사용하기 쉬운 것은 Database의 id이다. AUTO_INCREMENT된 id 값을 사용하거나, id가 아니라도 unique한 값이라면 key로 사용하면 된다. 

 

Robin Pokorny에 의하면, 아래 3가지를 만족하는 경우 index를 key로 써도 된다고 한다. (key 값으로 index를 꼭 설정해야겠다면, 아래의 조건을 확인하자)

  1. 배열과 각 요소가 static이며 computed 되지 않고, 변하지 않아야 한다. 
  2. 데이터 내부에 id로 쓸만한 unique 값이 없다. 
  3. 데이터가 결코 reordered 또는 filtered 되지 않는다. 
728x90
728x90

*하루동안 새롭게 알게된 부분, 에러를 해결한 방법 등을 작성하는 개발일기입니다. 다른 사람에게도 설명해줄 수 있도록 제 머릿속에 넣기 위해 정리를 시작하게 되었습니다. 

Public key retrieval is not allowed 에러(allowPublicKeyRetrieval=true 추가해도 에러가 발생한다면)

지난주에 'Public key retrieval is not allowed 에러 해결 방법'에 관한 글을 작성했다. 이 에러를 해결하기 위해서는 jdbc url allowPublicKeyRetrieval=true 설정을 추가하면 되었다. 

 

그런데 오늘 또 아래와 같이 'Public key retrieval is not allowed 에러'가 발생하였다. 

 

 

이미 jdbc urlallowPublicKeyRetrieval=true 설정이 되어 있었지만 'useSSL=false'가 가장 끝에 설정되어 있었다. 그래서 'allowPublicKeyRetrieval=true'를 가장 마지막 자리로 옮겨주었더니 에러가 해결되었다. 

 

// 수정 전
spring.datasource.url=jdbc:mysql://localhost:3306/db-name?useUnicode=true&characterEncoding=UTF-8&allowPublicKeyRetrieval=true&useSSL=false

// 수정 후
spring.datasource.url=jdbc:mysql://localhost:3306/db-name?useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true
728x90

+ Recent posts