만약 기존의 코드를 migration 할 때 props는 어떻게 처리할까?
물론 props를 import해온다고 해도 사용할 수 없다. 그렇다면 방법이 없을까? => X
바로 앞서 언급한 "인수"를 활용하면 된다.
import {computed, ref, watch} from "vue";
const useSearch = (props) => {
const enteredSearchTerm = ref('');
const activeSearchTerm = ref('');
const availableItems = computed(()=>{
let users = [];
if (activeSearchTerm.value) {
users = props.items.filter(props.filterFn);
} else if (props.items) {
users = props.items;
}
return users;
})
watch(enteredSearchTerm,(newValue)=>{
setTimeout(() => {
if (newValue === enteredSearchTerm.value) {
activeSearchTerm.value = newValue;
}
}, 300);
})
const updateSearch = (val) => {
enteredSearchTerm.value = val
}
}
export default useSearch;
const useSearch = (props) => {
const enteredSearchTerm = ref('');
const activeSearchTerm = ref('');
const availableItems = computed(()=>{
let users = [];
if (activeSearchTerm.value) {
users = props.items.filter((item) =>
item[props.searchProp].includes(activeSearchTerm.value)
);
} else if (props.items) {
users = props.items;
}
return users;
})
watch(enteredSearchTerm,(newValue)=>{
setTimeout(() => {
if (newValue === enteredSearchTerm.value) {
activeSearchTerm.value = newValue;
}
}, 300);
})
const updateSearch = (val) => {
enteredSearchTerm.value = val
}
return {enteredSearchTerm, availableItems, updateSearch}
}
const props = defineProps({
users : {
type: Object,
default : ()=>({id:String, fullName:String, projects:[]})
}
})
const enteredSearchTerm = ref('');
const activeSearchTerm = ref('');
const availableUsers = computed(()=>{
let users = [];
if (activeSearchTerm.value) {
users = props.users.filter((usr) =>
usr.fullName.includes(activeSearchTerm.value)
);
} else if (props.users) {
users = props.users;
}
return users;
})
watch(enteredSearchTerm,(newValue)=>{
setTimeout(() => {
if (newValue === enteredSearchTerm.value) {
activeSearchTerm.value = newValue;
}
}, 300);
})
const updateSearch = (val) => {
enteredSearchTerm.value = val
}
const sorting = ref(null);
const displayedUsers = computed(() =>{
if (!sorting.value) {
return availableUsers.value
}
return availableUsers.value.slice().sort((u1, u2)=>{
if (sorting.value === 'asc' && u1.fullName > u2.fullName) {
return 1;
} else if (sorting.value === 'asc') {
return -1;
} else if (sorting.value === 'desc' && u1.fullName > u2.fullName) {
return -1;
} else {
return 1;
}
})
})
const sort = (mode) => {
sorting.value = mode
}
const props = defineProps({
users : {
type: Object,
default : ()=>({id:String, fullName:String, projects:[]})
}
})
const {enteredSearchTerm, availableItems:availableUsers , updateSearch} = useSearch({items:props.users, searchProp:'fullName'})
const sorting = ref(null);
const displayedUsers = computed(() =>{
if (!sorting.value) {
return availableUsers.value
}
return availableUsers.value.slice().sort((u1, u2)=>{
if (sorting.value === 'asc' && u1.fullName > u2.fullName) {
return 1;
} else if (sorting.value === 'asc') {
return -1;
} else if (sorting.value === 'desc' && u1.fullName > u2.fullName) {
return -1;
} else {
return 1;
}
})
})
const sort = (mode) => {
sorting.value = mode
}
const props = defineProps({
user:{
type: Object,
default: ()=>({projects:String, fullName:String})
}
})
const {enteredSearchTerm, availableItems, updateSearch} = useSearch({items:props.user.projects, searchProp:'title'});
const hasProjects = computed(() => {
return props.user.projects && availableItems.value.length > 0
})
watch(props,()=>{
enteredSearchTerm.value = ''
})
const props = defineProps({
user:{
type: Object,
default: ()=>({projects:String, fullName:String})
}
})
const projects = props.user ? props.user.projects : []; <=여기
const {enteredSearchTerm, availableItems, updateSearch} = useSearch({items:projects, searchProp:'title'});
const hasProjects = computed(() => {
return props.user.projects && availableItems.value.length > 0
})
watch(props,()=>{
enteredSearchTerm.value = ''
})
하지만 여기서 끝! 이 아니다. 앞서 언급했듯 props.user까지는 reactive하지만 내부 프로퍼티로 들어가면 그 값은 더이상 ref한 값이 아니라고 하였다. 따라서 setup 함수가 최초로 실행됐을 때 projects 값이나 빈 배열을 가져오도록(pull) 설정했는데 그러면 끝! 즉, null이 되고 더 이상 값이 바뀌지 않는다는 것이다.
그래서 바뀌는 사용자에 반응하여 프로젝트를 업데이트해야하는데 가장 간단한 방법으로는 computed 메서드
이다.
const projects = computed(()=>{
return props.user ? props.user.projects : []
});
const {enteredSearchTerm, availableItems, updateSearch} = useSearch({items:projects, searchProp:'title'});
const props = defineProps({
user:{
type: Object,
default: ()=>({projects:String, fullName:String})
}
})
const {user} = toRefs(props);
const projects = computed(()=>{
return user.value ? user.value.projects : []
});
const {enteredSearchTerm, availableItems, updateSearch} = useSearch({items:projects, searchProp:'title'});
그런데 자세히 보면 useSearch에 넘기는 값인 projects는 ref한 값이고 이 ref한 값에 접근하려면 반드시 .value
가 있어야한다고 했다.
하지만 내가 작성해놓은 코드를 보면 그렇지 않다는 것을 확인할 수 있다. 따라서 해당 훅에서 props에 해당하는 값들에 .value
를 붙여줘야한다.
const useSearch = (props) => {
const enteredSearchTerm = ref('');
const activeSearchTerm = ref('');
const availableItems = computed(()=>{
let users = [];
if (activeSearchTerm.value) {
users = props.items.value.filter((item) =>
item[props.searchProp].includes(activeSearchTerm.value)
);
} else if (props.items.value) {
users = props.items.value;
}
return users;
})
watch(enteredSearchTerm,(newValue)=>{
setTimeout(() => {
if (newValue === enteredSearchTerm.value) {
activeSearchTerm.value = newValue;
}
}, 300);
})
const updateSearch = (val) => {
enteredSearchTerm.value = val
}
return {enteredSearchTerm, availableItems, updateSearch}
}
그리고 만약에 위와같이 만들어줬다면 위 useSearch 훅을 사용하는 모든 컴포넌트는 반드시 ref가 되어야한다.
즉, 결국 컴포넌트단에서 넘겨주는 모든 인수 값이 전부 ref해야지 좋다. 그래야만 데이터가 변함에 따라 로직이 실행되고 이는 바로 재실행되기 때문이다.
const props = defineProps({
users : {
type: Object,
default : ()=>({id:String, fullName:String, projects:[]})
}
})
const {enteredSearchTerm, availableItems:availableUsers , updateSearch} = useSearch({items:toRefs(props.users), searchProp:'fullName'}) => 잘못된예
const {users} = toRefs(props);
const {enteredSearchTerm, availableItems:availableUsers , updateSearch} = useSearch({items:users, searchProp:'fullName'}) => 잘된예
const sorting = ref(null);
const displayedUsers = computed(() =>{
if (!sorting.value) {
return availableUsers.value
}
return availableUsers.value.slice().sort((u1, u2)=>{
if (sorting.value === 'asc' && u1.fullName > u2.fullName) {
return 1;
} else if (sorting.value === 'asc') {
return -1;
} else if (sorting.value === 'desc' && u1.fullName > u2.fullName) {
return -1;
} else {
return 1;
}
})
})
const {enteredSearchTerm, availableItems, updateSearch} = useSearch({items:projects, searchProp:'title'});
const hasProjects = computed(() => {
return user.value.projects && availableItems.value.length > 0
})
watch(props,()=>{
enteredSearchTerm.value = ''
})
위와같은 코드는 지양해야한다.
무슨 말이냐 => useSeach같이 커스텀훅에서 넘어온 값을 사용중이 컴포넌트에서 임의로 바꾸면 안 된다는 것이다.
이유는 앞서 주구장창 말했던 코드를 이해하고 유지하기 쉽게 만들어야 하기 때문이다.
그래서 나온것이 별도로 값을 변경하는 함수를 선언하는 것이다.
다행히 우리는 useSearch에서 updateSeach라는 함수를 가져오기때문에
const {enteredSearchTerm, availableItems, updateSearch} = useSearch({items:projects, searchProp:'title'});
const hasProjects = computed(() => {
return user.value.projects && availableItems.value.length > 0
})
watch(props,()=>{
updateSearch('')
})
const useSort = (props) => {
const sorting = ref(null);
const displayedUsers = computed(() =>{
if (!sorting.value) {
return props.availableUsers.value
}
return props.availableUsers.value.slice().sort((u1, u2)=>{
if (sorting.value === 'asc' && u1.fullName > u2.fullName) {
return 1;
} else if (sorting.value === 'asc') {
return -1;
} else if (sorting.value === 'desc' && u1.fullName > u2.fullName) {
return -1;
} else {
return 1;
}
})
})
const sort = (mode) => {
sorting.value = mode
}
return{
displayedUsers, sort
}
}