페이지를 컴포넌트로 나누어주는 이유는 무엇일까?
바로 재사용성과 유지보수가 용이하다는 것 때문이다.
// 08-01-example-new
export default function ExampleNewPage() {
return (
<div>
<h1>등록페이지</h1>
제목: <input type="text" /><br />
내용: <input type="text" /><br />
<button> 등록하기 </button>
</div>
)
}
// 08-02-example-edit
export default function ExampleEditPage () {
return (
<div>
<h1>수정페이지</h1>
제목: <input type="text" /><br />
내용: <input type="text" /><br />
<button> 수정하기 </button>
</div>
)
}
우선 ‘ExampleNewPage’와 ‘ExampleEditPage’ 컴포넌트를 만들어 보았다.
이런식으로 등록컴포넌트와 수정컴포넌트를 따로 만들어주게 된다면 문제가 발생한다.
등록페이지가 바뀌게 된다 하더라도 수정페이지가 바뀌지 않는다.
즉, 등록페이지의 배경색을 바꾼다 하더라도 수정페이지에서는 바뀐 배경색이 적용되지 않는 것이다.
그렇다면 src폴더 안에 컴포넌트를 만들어 필요한 곳에 Import 하여 사용할 수 있게끔 하면 문제를 해결할 수 있다.
// src/components/unit/08-example/Example.js
export default function Example() {
return (
<div>
<h1>등록페이지</h1>
제목: <input type="text" /><br />
내용: <input type="text" /><br />
<button> 등록하기 </button>
</div>
)
}
컴포넌트를 Import 하여 사용하기 위해 각각 등록페이지와, 수정페이지를 만들었다.
// 08-03-example-component-new
import Example from '../../src/components/units/08-example/Example'
export default function ExampleComponentNew () {
return <Example />
}
// 08-04-example-component-edit
import Example from '../../src/components/units/08-example/Example'
export default function ExampleComponentEdit () {
return <Example />
}
이렇게 컴포넌트를 그저 불러와주기만 한다면 등록하기 페이지와 똑같이 나오게 된다.
그렇다면 수정 페이지와 등록 페이지를 구별할 수 있게 다르게 해주기 위해서는 어떻게 해야할까?
props 와 삼항연산자를 사용해주시면 가능하다.
각각의 페이지에서 isEdit을 수정하기 페이지일 경우 true, 등록하기 페이지일 경우 false로 주고 이 boolean값을 컴포넌트로 넘겨주는 것이다.
// 08-03-example-component-new
import Example from '../../src/components/units/08-example/Example'
export default function ExampleComponentNew () {
return <Example isEdit={false} />
}
// 08-04-example-component-edit
import Example from '../../src/components/units/08-example/Example'
export default function ExampleComponentEdit () {
return <Example isEdit={true} />
}
src폴더 안의 Example.js 파일도 isEdit의 boolean 타입에 따라 등록과 수정이 나오게끔 props와 삼항연산자를 사용해 주자.
// src/components/unit/08-example/Example.js
export default function Example(props) {
return (
<div>
<h1>{props.isEdit ? "수정하기" : "등록하기"}</h1>
제목: <input type="text" /><br />
내용: <input type="text" /><br />
<button> {props.isEdit ? "수정완료" : "등록완료"} </button>
</div>
)
}
이렇게 컴포넌트에서 받은 isEdit를 다시 프레젠터로 넘겨주어 이 값에 따라 true이면 수정, false이면 등록이 보이도록 해준다면 컴포넌트를 재사용해서 등록페이지와 수정페이지를 컴포넌트 하나로 만들수 있다.
isEdit 이 true인 경우 수정하는 컴포넌트로 재사용
isEdit 이 false인 경우 등록하는 컴포넌트로 재사용
우리가 게시물을 수정을 하게되면 수정한 값만 업데이트 되어야 한다.
하지만 기존값이 유지되도록 하지 않고 수정을 하게되면 모든 부분이 업데이트 되는것을 확인할 수 있다.
그러나 실제 게시글은 수정된 부분만 업데이트 돼야 하므로 이 부분을 보완해야 하는것이 필수다.
❗️ 수정 인풋에 내가 적었던 글 데려오기
→ defaultValue에 기존값을 넣어두면 쉽게 해결할 수 있다.
defaultValue란?
→ 인풋태그의 속성 중 하나
문제는 defaultValue에 기존의 데이터를 데리고 오는 과정에서 fetch를 해주어야 하는데 , 우리는 해당 컴포넌트를 재사용 하기 때문에 container에서 fetch 를 하게되면 등록과 수정 모두에게 적용됩니다.
그렇기 때문에 수정 페이지만 적용되도록 fetch는 페이지 컴포넌트에서하고, 해당 data를 props로 넘겨주면 수정 페이지로 들어갔을 때 값이 그대로 존재하는 것을 확인할 수 있다.
defaultValue를 줬음에도 불구하고 수정하기를 누르면, 수정하지 않은 부분에 defaultValue로 들어가는 것이 아닌 빈 값이 들어가게 된다.
이는 state의 초깃값 때문이다.
defaultValue는 실제 state가 아닌 input의 속성이기 때문에 실제 눈에 보이는 것과 달리 state에는 저장되지 않는다.
❗️ 그럼 어떻게 해결해야 할까?
→ 해결하는 방법은 크게 두가지가 있다.
1. defaultValue를 state의 초깃값으로 넣기.(비효율적)
2. mutation 할 때 변경된 부분만 보내주기.(효율적)
조금 더 효율적인 mutation 할 때, 변경된 부분만 보내주기를 사용하면 된다.
아래는 변경된 부분만 뮤테이션으로 보내주는 방법이다.
// 뮤테이션에 변경된 부분만 보내주기
cosnt xxx = async()=>{
const myVariables = {
number : Number(router.query.mynumber),
}
//변경된 값만 객체에 key와 value 추가해주기
if(myWriter !== ""){ myVariables.writer = myWriter}
if(myTitle !== ""){ myVariables.title = myTitle}
if(myContents !== ""){ myVariables.contents = myContents}
//뮤테이션 보내기
cosnt result = await ww({
variables : myVariables
})
}
코드를 보면,
1. myVarialbes라는 빈객체를 선언해 꼭 들어가야 하는 number를 넣어두고
2. 조건문을 이용해 state가 빈값이 아닐 경우에만 객체에 key와 value를 추가해 준다.
이렇게 직접 만들어둔 myVariables 객체에는 변경된 값만 객체에 들어가게 된다.
그리고 그렇게 완성된 객체를 variables에 넣어서 mutation을 날려주면 된다.