redux 연결 구성 요소는 언제 다시 렌더링할지 어떻게 알 수 있습니까?


94

나는 아마도 매우 명백한 것을 놓치고 있고 스스로를 정리하고 싶습니다.

여기 내 이해가 있습니다.
순진한 반응 구성 요소에는 states& props. 로 업데이트 하면 전체 구성 요소 statesetState다시 렌더링됩니다. props대부분 읽기 전용이며 업데이트하는 것은 의미가 없습니다.

redux 저장소를 구독하는 반응 구성 요소에서, 같은 것을 통해 store.subscribe(render)저장소가 업데이트 될 때마다 분명히 다시 렌더링됩니다.

반응-REDUX는 도우미를 가지고 connect()그 같이 actionCreators (구성 요소에 대한 관심의) 상태 트리를 분사 부분 props일반적으로 같은 것을 통해 구성 요소에

const TodoListComponent = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

그러나이 것을 이해 setState(가)를 위해 필수적이다 TodoListComponentREDUX 상태 트리 변경 (재 렌더링)에 반응하는, 나는 어떤 찾을 수 없습니다 state또는 setState에서 관련 코드 TodoList구성 요소 파일을. 다음과 같이 읽습니다.

const TodoList = ({ todos, onTodoClick }) => (
  <ul>
    {todos.map(todo =>
      <Todo
        key={todo.id}
        {...todo}
        onClick={() => onTodoClick(todo.id)}
      />
    )}
  </ul>
)

누군가 내가 놓친 것에 대해 올바른 방향으로 나를 가리킬 수 있습니까?

추신 나는 redux 패키지 와 함께 번들로 제공되는 할 일 목록 예제를 따르고 있습니다.

답변:


116

connect함수는 상점을 구독하는 랩퍼 구성 요소를 생성합니다. 작업이 전달되면 래퍼 구성 요소의 콜백에 알림이 전송됩니다. 그런 다음 mapState함수 를 실행 하고이 시간의 결과 객체와 지난 시간의 결과 객체를 얕게 비교 합니다 (따라서 동일한 값으로 redux 저장소 필드 를 다시 작성 하는 경우 다시 렌더링을 트리거하지 않습니다). 결과가 다르면 결과를 "실제"구성 요소 "에 소품으로 전달합니다.

Dan Abramov는 최적화 작업을 보여주지는 않지만 기본적인 아이디어를 보여주는 connectat ( connect.js ) 의 매우 단순화 된 버전을 작성했습니다 . 또한 몇 가지 관련 아이디어를 논의 하는 Redux 성능 에 대한 여러 기사에 대한 링크가 있습니다 .

최신 정보

React-Redux v6.0.0 은 연결된 구성 요소가 저장소에서 데이터를받는 방식에 몇 가지 주요 내부 변경 사항을 적용했습니다.

그 일환으로 connectAPI와 내부 기능이 작동하는 방식과 시간이 지남에 따라 어떻게 변했는지 설명하는 게시물을 작성했습니다 .

관용적 Redux : React-Redux의 역사와 구현


감사! 당신은 요 전에 HN에서 나를 도운 사람과 같은 사람 입니까 -news.ycombinator.com/item?id=12307621 유용한 링크가 있습니까? 만나서 반가워요 :)
Joe Lewis

4
그래, 나야 그 :) 내가 보내는 방법 온라인으로 돌아 오는에 대한 논의를 찾는 너무 많은 시간을 - SO 레딧, HN, 중간, 및 기타 다양한 장소. 도와 주셔서 감사합니다! (또한 참고로, Discord의 Reactiflux 채팅 채널을 적극 권장합니다. 많은 사람들이 그곳에서 놀고 질문에 답합니다. 저는 보통 미국 동부 표준시 저녁에 온라인 상태입니다. 초대 링크는 reactiflux.com에 있습니다.)
markerikson 2016

이것이 질문에 대답했다고 가정하고 대답을 수락 하시겠습니까? :)
markerikson 2016

객체 자체 또는 이전 / 이후 객체의 속성을 비교합니까? 후자의 경우 첫 번째 수준 만 확인합니다. "얕은"이라는 뜻입니까?
Andy

예, "얕은 동등성 검사"는 각 개체의 첫 번째 수준 필드를 비교하는 것을 의미합니다 prev.a === current.a && prev.b === current.b && ...... 즉, 데이터 변경이 새로운 참조로 이어진다 고 가정합니다. 즉, 직접 변형 대신 변경할 수없는 데이터 업데이트가 필요합니다.
markerikson

14

내 대답은 약간 왼쪽 필드에서 벗어났습니다. 저를이 게시물로 이끈 문제에 대해 밝힙니다. 제 경우에는 새로운 소품을 받았음에도 불구하고 앱이 다시 렌더링되지 않는 것처럼 보였습니다.
React 개발자는이 자주 묻는 질문에 대해 (스토어)가 변형 된 경우 99 %의 시간이 반응이 다시 렌더링되지 않는 이유에 대한 답변을 받았습니다. 그러나 다른 1 %에 대해서는 아무것도 없습니다. 여기서 돌연변이는 그렇지 않았습니다.


TLDR;

componentWillReceivePropsstate새로운 props.

엣지 케이스 : 일단 state업데이트, 다음 응용 프로그램이 않습니다 다시 렌더링!


앱이 state요소를 표시 하는 데만 사용하는 경우 props업데이트 할 수 있지만 업데이트 할 수 state없으므로 다시 렌더링 할 수 없습니다.

나는 redux state에서 props받은 것에 의존했다 store. 필요한 데이터가 아직 스토어에 없으므로에서 가져 왔습니다 componentDidMount. 내 구성 요소가 mapStateToProps를 통해 연결되어 있기 때문에 감속기가 저장소를 업데이트했을 때 소품을 다시 얻었습니다. 그러나 페이지는 렌더링되지 않았고 상태는 여전히 빈 문자열로 가득 차있었습니다.

예를 들어 사용자가 저장된 URL에서 "게시물 편집"페이지를로드했다고 가정합니다. postIdURL에서에 액세스 할 수 있지만 정보가 store아직 입력되지 않았으므로 가져옵니다. 페이지의 항목은 제어 된 구성 요소이므로 표시하는 모든 데이터는에 state있습니다.

redux를 사용하여 데이터를 가져오고 저장하고 구성 요소를 connect편집했지만 앱에 변경 사항이 반영되지 않았습니다. 자세히 살펴보면 props수신되었지만 앱이 업데이트되지 않았습니다. state업데이트하지 않았습니다.

글쎄, props업데이트 및 전파되지만 state그렇지 않습니다. state업데이트 를 구체적으로 알려야 합니다.

이에 할 수 없어 render(), 그리고 componentDidMount이미의 사이클을 완료했다.

componentWillReceivePropsstate변경된 prop값 에 의존하는 속성을 업데이트하는 곳 입니다.

사용 예 :

componentWillReceiveProps(nextProps){
  if (this.props.post.category !== nextProps.post.category){
    this.setState({
      title: nextProps.post.title,
      body: nextProps.post.body,
      category: nextProps.post.category,
    })
  }      
}

수십 개의 다른 게시물, 블로그 및 리포지토리에서 언급하지 않은 솔루션에 대해 깨달은이 기사에 한마디 부탁드립니다. 이 모호한 문제에 대한 답을 찾는 데 어려움을 겪은 다른 사람은 다음과 같습니다.

ReactJs 구성 요소 수명주기 방법 — 심층 분석

componentWillReceiveProps업데이트 state와 동기화를 유지하기 위해 업데이트 할 곳 props입니다.

일단 state업데이트, 다음 에 따라 필드 state DO 다시 렌더링!


3
에서 React 16.3이후, 당신은 해야 사용 getDerivedStateFromProps대신을 componentWillReceiveProps. 그러나 실제로 여기에
kyw

상태가 변경 될 때마다 작동하지 않습니다. componentWillReceiveProps가 작동하지 않는 경우가 많아서 작동합니다. 특히, 다중 레벨 중첩 또는 복잡한 props는 ID가있는 컴포넌트를 할당하고 변경을 트리거하고 새로운 데이터를 다시 렌더링하기 위해 상태를 업데이트해야합니다
May'Habit

0

이 답변은 You Probably Do n't Need Derived State (2018 년 6 월 7 일) 라는 제목의 Brian Vaughn의 기사 요약입니다 .

소품에서 상태를 가져 오는 것은 모든 형태의 반 패턴입니다. 이전 componentWillReceiveProps및 최신 getDerivedStateFromProps.

props에서 상태를 파생하는 대신 다음 솔루션을 고려하십시오.

두 가지 모범 사례 권장 사항

권장 사항 1. 완전히 제어되는 구성 요소
function EmailInput(props) {
  return <input onChange={props.onChange} value={props.email} />;
}
권장 사항 2. 키가있는 완전히 제어되지 않는 구성 요소
// parent class
class EmailInput extends Component {
  state = { email: this.props.defaultEmail };

  handleChange = event => {
    this.setState({ email: event.target.value });
  };

  render() {
    return <input onChange={this.handleChange} value={this.state.email} />;
  }
}

// child instance
<EmailInput
  defaultEmail={this.props.user.email}
  key={this.props.user.id}
/>

어떤 이유로 든 권장 사항이 상황에 맞지 않는 경우 두 가지 대안이 있습니다.

대안 1 : ID 소품으로 제어되지 않는 구성 요소 재설정
class EmailInput extends Component {
  state = {
    email: this.props.defaultEmail,
    prevPropsUserID: this.props.userID
  };

  static getDerivedStateFromProps(props, state) {
    // Any time the current user changes,
    // Reset any parts of state that are tied to that user.
    // In this simple example, that's just the email.
    if (props.userID !== state.prevPropsUserID) {
      return {
        prevPropsUserID: props.userID,
        email: props.defaultEmail
      };
    }
    return null;
  }

  // ...
}
대안 2 : 인스턴스 메서드를 사용하여 제어되지 않는 구성 요소 재설정
class EmailInput extends Component {
  state = {
    email: this.props.defaultEmail
  };

  resetEmailForNewUser(newEmail) {
    this.setState({ email: newEmail });
  }

  // ...
}

-2

내가 redux 가하는 일 만 알고 있기 때문에 구성 요소가 변경된 상태에 종속되어 있으면 componentWillRecieveProps를 호출하고 구성 요소를 강제로 업데이트해야합니다.

1-store State change-2-call (componentWillRecieveProps (() => {3-component state change}))

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.