SOLID JavaScript에 `S` 입력
S
- SRP(Single-Responsibility Principle)는 SOLID
주체가 적용되는 첫 번째 설계 주체입니다.SOLID is an Object oriented design principal. It stands for:
S
- Single-responsiblity PrincipleO
- Open-closed PrincipleL
- Liskov Substitution PrincipleI
- Interface Segregation PrincipleD
- Dependency Inversion PrincipleThe principals were originally created and promoted by Robert Martin (aka Uncle Bob).
SRP는 단순히 클래스와 함수가 단일 책임만 가져야 한다고 명시합니다. 이것은 원칙적으로는 매우 쉽게 들리지만 실제로는 특히 React에서는 약간 더 미묘한 차이가 있을 수 있습니다. 아티스트와 아티스트의 세부 사항을 처리하는 클래스로 설명하겠습니다.
// Wrong!
class Artist {
constructor(id) {
this.id = id;
this.getBio()
this.getSingles();
this.getAlbums()
}
getBio() {
fetch(`/artist/${this.id}/bio/`)
//... do stuff with data
}
getSingles() {
fetch(`/artist/${this.id}/singles/`)
//... do stuff with data
}
getAlbums() {
fetch(`/artist/${this.id}/articles/`)
//... do stuff with data
}
}
const theArtist = new Artist('formerlyKnownAsPrince');
이 예에서
Artist
클래스는 여러 가지를 담당합니다. 아티스트를 대표해야 하지만 약력, 싱글 및 앨범을 가져오는 책임도 있습니다.이것이 왜 나쁜가요? 예를 들어
getBio
와 같은 추가 속성을 갖기 위해 this.fetchedData = true
를 업데이트해야 하는 경우 클래스의 다른 부분이 손상될 수 있습니다. 정말 조심해서 this.fetchedBio
와 같은 더 구체적인 변수를 사용할 수 있지만 애플리케이션과 클래스/함수가 복잡할수록 이를 관리하고 추적하기가 더 어려워집니다. 대신 책임을 분할하고 하나의 책임만 처리하는 다른 클래스와 함수를 만들 수 있습니다.// Right!
function getBio(id) {
fetch(`/artist/${id}/bio/`)
//... do stuff with data
return bio;
}
function getSingles(id) {
fetch(`/artist/${id}/singles/`)
//... do stuff with data
return singles;
}
function getAlbums(id) {
fetch(`/artist/${this.id}/articles/`)
//... do stuff with data
return albums;
}
class Artist {
constructor(bio, singles, albums) {
this.bio = bio;
this.singles = singles;
this.albums = albums;
}
}
function getArtistDetails(id) {
const bio = getBio(id);
const singles = getSingles(id);
const albums = getAlbums(id);
return { bio, singles, albums };
}
const { bio, singles, albums } = getArtistDetails('formerlyKnownAsPrince')
const theArtist = new Artist(bio, singles, albums);
이제 Artist 클래스를 분할하고 메서드를 순수 함수로 옮겼습니다. 각 사람에게는 단일한 책임이 있습니다.
하지만 3가지(바이오, 싱글, 앨범)를 가져오는 역할을 하는
getArtistDetails
함수는 어떻습니까? 데이터를 가져오는 것이 정말 하나의 책임이기 때문에 괜찮습니다!이제 해당 아티스트를 저장하려면 하나의 책임만 가질 수 있는 새 클래스
Saver
를 만들 수 있습니다! 우리는 Artist에 어떤 다른 메서드가 있는지 또는 어떤 속성을 가질 수 있는지에 대해 걱정할 필요가 없습니다. Artist
를 가져와서 다른 속성이나 메서드를 손상시킬 염려 없이 저장할 수 있습니다.//... the rest
const theArtist = new Artist(bio, singles, albums); // from before
class Saver {
save (data) {
// something to save the data
}
}
const saver = new Saver();
saver.save(theArtist);
반응하다
component classes
또는 functional components
를 생성하든 동일한 원칙이 반응에 적용됩니다.// Wrong
const Artist = ({ id }) => {
const [bio, setBio] = useState(null);
const [singles, setSingles] = useState([]);
const [albums, setAlbums] = useState([]);
useEffect(()=> {
fetch(`/artist/${id}/bio/`)
.then(data => {
setBio(data);
})
}, [id])
useEffect(()=> {
fetch(`/artist/${id}/singles/`)
.then(data => {
setSingles(data);
})
}, [id])
useEffect(()=> {
fetch(`/artist/${id}/albums/`)
.then(data => {
setAlbums(data);
})
}, [id])
const singlesList = singles.map(single => (
<li key={single.id}>{single.title} - {single.releaseDate}</li>
));
const albumsList = albums.map(album => (
<li key={album.id}>{album.title} <img src={album.artWorkUrl} /></li>
));
return (
<div>
{ bio ? <h2>{bio.name}</h2> : null }
<ul>{singlesList}</ul>
<ul>{albumsList}</ul>
</div>
)
}
구성 요소에 문제가 있는 몇 가지 일이 있습니다. 데이터 검색/상태 논리가 있고 모두 동일한 구성 요소에 프레젠테이션 논리가 있습니다. 주요 구성 요소와 함께 각 목록의 렌더링이 있습니다. 너무 많은 일을 하기 때문에 컴포넌트를 재사용하거나 다른 용도로 변경하기가 매우 어렵습니다.
고치자! 프레젠테이션 UI 및 논리에서 데이터 논리를 분리합니다. UI의 각 부분에는 전용 단일 책임 구성 요소가 있습니다.
const Bio = ({bio}) => {
if (!bio) return null;
return <h2>{ bio.name}</h2>;
}
const SingleList = ({singles}) => {
const singlesList = singles.map(single => (
<li key={single.id}>{single.title} - {single.releaseDate}</li>
));
return (
<ul>
{singlesList}
</ul>
)
}
const AlbumList = ({albums}) => {
const albumsList = albums.map(album => (
<li key={album.id}>{album.title} <img src={album.artWorkUrl} /></li>
));
return (
<ul>
{albumsList}
</ul>
)
}
const ArtistCard = ({bio, singles, albums}) => (
<div>
<Bio bio={bio} />
<SingleList singles={singles} />
<AlbumList albums={albums} />
</div>
)
const Artist = ({ id }) => {
const [bio, setBio] = useState(null);
const [singles, setSingles] = useState([]);
const [albums, setAlbums] = useState([]);
useEffect(()=> {
fetch(`/artist/${id}/bio/`)
.then(data => {
setBio(data);
})
}, [id])
useEffect(()=> {
fetch(`/artist/${id}/singles/`)
.then(data => {
setSingles(data);
})
}, [id])
useEffect(()=> {
fetch(`/artist/${id}/albums/`)
.then(data => {
setAlbums(data);
})
}, [id])
return <ArtistCard bio={bio} singles={singles} albums={albums} />
}
이제 다른 위치에서 UI를 재사용할 수 있음을 의미합니다. 예를 들어 아티스트 목록에
ArtistCard
를 사용할 수 있습니다. 동일한 UI를 다시 만들거나 논리를 처리할 필요가 없었습니다. 그냥 작동합니다 ™ .const ArtistList = ({listOfArtists}) => {
const artists = listOfArtists.map(({bio, singles, albums}) => (
<ArtistCard bio={bio} singles={singles} albums={albums} />
));
return <div>{artists}</div>;
}
우리가 만든 구성 요소는 모두 순수하기 때문에(동일한 입력이 주어지면 동일한 값을 반환함) 이것은 우리가 2가지 매우 유용한 이점을 얻는다는 것을 의미합니다.
memo
를 사용하여 쉽게 최적화할 수 있습니다. 요약
단일 책임 원칙은 클래스, 기능 및 구성 요소를 보다 안정적이고 재사용 가능하며 최적화 가능하고 테스트 가능하게 만들기 때문에 배우고 사용할 수 있는 훌륭한 기본 원칙입니다.
다음 사항을 기억하십시오.
Reference
이 문제에 관하여(SOLID JavaScript에 `S` 입력), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/designer023/putting-the-s-in-solid-javascript-l82텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)