React의 명령적 크리프

반응
반응 구성 요소가 특정 시점에서 어떻게 표시되어야 하는지 설명하고 기본 데이터가 변경될 때 모든 UI 업데이트를 관리할 수 있는 선언적 프레임워크입니다. UI에 필요한 최소 상태 세트만 유지하고 요청 시 다른 모든 것을 컴퓨팅하는 등 상태 관리에 대한 모범 사례를 따르면 일반적으로 훨씬 덜 필수적인 코드를 작성합니다. 이 방법을 따르면 일관되지 않은 UI 상태와 관련된 전체 버그 클래스를 제거할 수 있다는 이점도 있습니다. 그러나 구성 요소 상태의 속성이 항상 다른 것에서 계산되지 않는 방식으로 서로 의존할 수 있는 상황이 있으며 이러한 제약 조건 내에서 상태를 유지하려는 직관적인 시도로 인해 끔찍한 명령형 코드가 도입될 수 있습니다. 이 기사에서는 그러한 시나리오를 보여주고 상태 일관성을 유지하는 보다 선언적인 방법을 제안합니다.

우리는 항목 목록을 렌더링하는 구성 요소를 원합니다. 항목을 선택하여 체크된 상태로 전환할 수 있습니다. 항목이 선택된 경우 구성 요소는 클릭하면 선택된 항목만 표시하는 "선택됨" 탭을 표시합니다. 우리는 두 가지 상태 속성이 있는 구성 요소를 사용하여 이를 구현합니다. 첫 번째는 선택된 항목 세트를 보유하는 checkSet이고 두 번째는 onlyShowChecked입니다. 후자의 속성이 true인 경우 구성 요소는 선택된 항목만 표시하고 선택됨 탭은 "활성"입니다. 간단해 보이지만 코드는 다음과 같습니다.

var Selector = React.createClass({ getInitialState() { return { checkSet: Immutable.Set(this.props.init), onlyShowChecked: false, }; }, setShowChecked(bool) { this.setState({ onlyShowChecked: bool }) ; },ggleChecked(o) { varcheckSet = this.state.checkedSet;checkedSet =checkedSet[checkedSet.contains(o) ? 'delete' : 'add'](o);this.setState({checkedSet }); } , render() { var checkSet = this.state.checkedSet; var onlyShowChecked = this.state.onlyShowChecked; var someChecked = checkSet.size > 0; var items = this.props.items.toSeq(); if (onlyShowChecked) { items = items.filter(o => checkSet.contains(o)); } return (

{일부확인됨 &&

}

{this.props.title} {items.map((o, i) => ( )).toArray()}
    ); } }); var items = Immutable.List(['Angular', 'Backbone', 'Ember', 'Knockout', 'React']); React.render(, document.body);

JS 빈
좋아 보이지만 바람직하지 않은 상태가 있습니다. 선택됨 탭에 있고 모든 항목을 선택 취소하면 UI에 항목이 표시되지 않고 더 이상 활성 탭이 없습니다. 마지막 항목을 선택 취소할 때마다 자동으로 모두 표시 탭으로 다시 전환하여 이 문제를 해결하고 싶을 것입니다. 해당 동작을 구현하는 가장 확실한 위치는 물론 우리를 이 상태로 만든 동작입니다. 즉,ggleChecked에서 우리는 마지막 항목을 선택 취소했는지 확인하고 그렇다면 onlyShowChecked를 false로 설정하고 싶습니다. 수정된 ToggleChecked는 다음과 같습니다.

  토글체크(o) { var checkSet = this.state.checkedSet; checkSet = checkSet[checkedSet.contains(o) ? '삭제' : '추가'](o); var onlyShowChecked = this.state.onlyShowChecked; if (checkedSet.isEmpty()) onlyShowChecked = false; this.setState({checkedSet, onlyShowChecked }); },

물론 해당 시나리오를 다시 실행해 보면 원하는 대로 작동할 것입니다. JS 빈
그러나 이 접근 방식에는 몇 가지 잘못된 점이 있습니다. 이제 ToggleChecked 함수에는 여러 가지 책임이 있습니다. 항목의 확인된 상태를 전환하는 것 외에도 이제 onlyShowChecked 속성도 설정합니다. 이 코드를 읽는 다음 개발자는 이전 버전에 비해 한눈에 이해하지 못할 것입니다. 그들은 이 검사가 왜 도입되었는지 생각해야 하며 기능을 수정하거나 추가할 때 항상 이러한 극단적인 경우를 염두에 두어야 합니다.
이제 모든 항목을 한 번에 선택 취소하는 버튼을 추가하면 어떤 일이 발생할 수 있는지 생각해 보세요. 이 버튼은 checkSet을 지우는 uncheckAll 함수를 호출합니다.
JS 빈
실제로 이 새 버튼을 사용하여 선택됨 탭에 있는 동안 모든 항목을 선택 취소할 수 있으므로 원치 않는 상태로 다시 들어가는 것이 가능합니다. 이 시점에서는 버그로 간주되며 이를 해결할 수 있는 몇 가지 직관적인 방법이 있습니다.
한 가지 확실한 해결 방법은 우리가 ToggleChecked에 도입한 것과 동일한 검사를 인라인하는 것입니다. 그러나 이렇게 하면 다시 uncheckAll의 책임이 추가되고 로직을 복제하는 것은 유지 관리에 결코 좋지 않습니다.
또 다른 방법은 체크된 항목을 반복하고 각각에 대해ToggleChecked를 호출하는 것입니다. 이것은 효과가 있지만 필요한 것보다 훨씬 더 많은 일을 하고 있는 것처럼 느껴질 것입니다. 그리고 함수 호출에서 setState를 여러 번 호출할 때 렌더링 동작을 누가 예측할 수 있습니까? 또한 우리가 할 유일한 이유는 고려 이렇게 하는 이유는 우리가 알고있다 ToggleChecked에는 우리가 원하는 부작용이 있으며, 이렇게 하면 두 기능이 긴밀하게 결합됩니다.
어느 쪽이든, 지금부터 몇 달 후에 각 항목의 선택된 상태를 반전시키는 버튼을 추가하여 항목을 전환하는 세 번째 방법을 도입하고 싶다고 가정해 보겠습니다. 이는 모든 항목이 선택된 경우 사실상 모두 선택 취소입니다. 이 시점에서는 구성 요소가 바람직하지 않은 상태에 빠지는 것을 방지하기 위해 코드를 추가했으며 버그를 다시 도입하는 것이 너무 쉽다는 사실을 잊어버리는 것이 당연합니다.
근본적인 문제는 React에서 상태 속성 간의 종속성을 선언적으로 설명할 수 있는 명확한 방법이 없다는 것입니다. 즉, 우리의 경우에는 selectedSet가 비어 있을 때 onlyShowChecked가 참이 되어서는 안 됩니다. 따라서 불변성을 유지하기 위해 우리는 jQuery로 작성했던 명령형 DOM 조작을 연상시키는 명령형 상태 조작을 작성하게 되었으며, 이는 필연적으로 유지 관리 문제로 이어질 것입니다. 이것이 바로 내가 명령적 크리프라고 부르는 것입니다.
Angular 또는 관찰 가능 항목을 제공하는 다른 프레임워크에서는 showSelected를 올바른 상태로 유지하기 위해 checkSet 속성을 관찰할 수 있습니다. React에서 종속 상태를 관리하는 가장 좋은 방법은 렌더링 함수의 맨 위에 있는 상태를 직접 변경하는 것입니다.

  render() { if (this.state.checkedSet.isEmpty() && this.state.onlyShowChecked) { this.state.onlyShowChecked = false; } // ... }

이제 우리는 이것이 모든 React 애플리케이션에서 나쁜 습관처럼 보인다는 것을 인정하지만, 이 결론에 가볍게 도달하지는 않았습니다. 우리는 shouldComponentUpdate 라이프사이클 메소드에서 상태 관리를 시도했지만 이미 shouldComponentUpdate를 제공하는 믹스인을 사용할 때, 상태가 일반 자바스크립트 객체 대신 Immutable일 때, forceUpdate가 shouldComponentUpdate를 완전히 우회하는 등 여러 가지 비호환성을 도입했습니다.
렌더링 기능의 상단에서 종속 상태를 관리함으로써 이러한 비호환성을 처리할 필요가 없습니다. 이점은 UI 버그의 근본 원인을 제거했으며 개발자가 종속 상태 속성에 대한 모든 규칙을 한 곳에 보관하도록 권장한다는 것입니다.

비슷한 게시물