반응 : 소품이 변경 될 때 왜 하위 구성 요소가 업데이트되지 않는가


135

다음 의사 코드 예제에서 컨테이너가 foo.bar를 변경할 때 Child가 다시 렌더링되지 않는 이유는 무엇입니까?

Container {
  handleEvent() {
    this.props.foo.bar = 123
  },

  render() {
    return <Child bar={this.props.foo.bar} />
}

Child {
  render() {
    return <div>{this.props.bar}</div>
  }
}

forceUpdate()컨테이너에서 값을 수정 한 후 호출해도 Child는 여전히 이전 값을 표시합니다.


5
이 코드입니까? 유효한 React 코드가 아닌 것 같습니다

컨테이너 구성 요소에서 props 값이 변경되어서는 안되며 setState에 의해 부모 구성 요소에서 변경되어야하며 그 상태는 컨테이너 props에 매핑되어야합니다.
— Piyush Patel

<Child bar = {... this.props.foo.bar} />와 같은 스프레드 연산자를 사용하십시오
— Sourav Singh

@AdrianWydmanski와 5 명을 찬성했습니다 : en.wikipedia.org/wiki/Pseudocode
— David Newcomb

@PiyushPatel 소품은 의사 코드의 예와 같이 구성 요소를 제자리에 다시 렌더링 할 때 업데이트됩니다. 이것의 또 다른 예는를 사용 <Route exact path="/user/:email" component={ListUserMessagePage} />하는 것과 같은 것입니다. 같은 페이지의 링크는 새 인스턴스를 만들고 일반적인 수명주기 이벤트를 실행하지 않고 소품을 업데이트합니다.
— David Newcomb

답변:


94

속성 'key'가 이름과 같도록 하위를 업데이트하십시오. 키가 변경 될 때마다 구성 요소가 다시 렌더링됩니다.

Child {
  render() {
    return <div key={this.props.bar}>{this.props.bar}</div>
  }
}

5
고마워 redux 상점을 사용하고 있었고 키를 추가 할 때까지 구성 요소를 다시 렌더링 할 수 없었습니다. (uuid 라이브러리를 사용하여 임의의 키를 생성했으며 작동했습니다.)
— Maiya

후크를 사용하면 기존 배열에서 상태를 설정할 때 자녀가 다시 렌더링하지 않습니다. 내 (아마도 나쁜 생각) 해킹은 동시에 더미 소품의 상태를 설정하고 useEffect 종속성 배열에 추가하는 것 [props.notRenderingArr, props.dummy]입니다. 배열의 길이가 항상 변경되면 useEffect 종속성 배열을로 설정할 수 [props.notRenderingArr.length]있습니다.
— hipnosis

5
이것도 내가 필요한 것입니다. 나는 언제 key필요한지에 대해 의아해 합니다 setState. 부모님을 의지하는 자녀가 있지만 다시 렌더링하지 않습니다.
— dcsan

좋은 대답입니다. 그러나 왜 이런 행동을 하는가?
— Rishav

1
인덱스를 키로 사용했지만 제대로 작동하지 않았습니다. 이제 나는 uuid를 사용하고 있으며 완벽합니다 :) @Maiya 덕분에
— Ali Rehman

90

부모의 소품이 바뀌면 자녀가 다시 렌더링하지 않지만 STATE가 변경되면 :)

당신이 보여주는 것은 이것입니다 : https://facebook.github.io/react/tips/communicate-between-components.html

소품을 통해 부모에서 자식으로 데이터를 전달하지만 거기에는 렌더링 논리가 없습니다.

일부 상태를 상위로 설정 한 다음 상위 변경 상태에서 하위를 다시 렌더링해야합니다. 도움이 될 수 있습니다. https://facebook.github.io/react/tips/expose-component-functions.html


5
setState가 다시 렌더링을 유발하지만 forceUpdate가 아닌 이유는 무엇입니까? 또한 주제가 거의 없지만 소품이 redux에서 전달되고 상태가 조치를 통해 업데이트되면 구성 요소는 어떻게 업데이트됩니까?
— Tuomas Toivonen

전달한 소품이 여전히 존재하는 구성 요소를 업데이트하더라도 소품은 업데이트되지 않습니다. Flux는 또 다른 주제입니다 :)
— François Richard

3
state! = props 더 읽어야합니다. 소품으로 업데이트하지 마십시오
— François Richard

당신은 소스 코드에서 직접 볼 수 있습니다, 그것은 단순히 같은 과정이 아닙니다
— Webwoman

그래서 당신이 여기 말했다 중 하나를 변경되었다거나 내가 제대로 이해하지 않았다, 나는, 그런데 그것에 대한 질문을했다 stackoverflow.com/questions/58903921/...
— ILoveReactAndNode

50

나는 같은 문제가 있었다. 이것은 나의 해결책이며, 그것이 좋은 습관인지 확실하지 않습니다.

state = {
  value: this.props.value
};

componentDidUpdate(prevProps) {
  if(prevProps.value !== this.props.value) {
    this.setState({value: this.props.value});
  }
}

UPD : 이제 React Hooks를 사용하여 동일한 작업을 수행 할 수 있습니다 : (컴포넌트가 함수 인 경우에만)

const [value, setValue] = useState(propName);
// This will launch only if propName value has chaged.
useEffect(() => { setValue(propName) }, [propName]);

3
이 간단한 말할 것도없고, definetely 정답
— Guilherme 페레이라

1
나는 또한이 접근법을 사용하고 있습니다.
— rawlyly

@ vancy-pants componentDidUpdate이 경우에는 Child 구성 요소에 들어갑니다.
— Nick Friskel

4
하위 구성 요소에서 소품을 상태로 변환 할 필요가 없으며 변환해서는 안됩니다. 소품을 직접 사용하십시오. 에서 FunctionComponents이를 자동으로 소품 변경하는 경우 하위 구성 요소를 업데이트합니다.
— oemera

1
이 접근 방식은 부모 상태에서 파생 된 하위 구성 요소에 소품이있는 경우에도 작동합니다.
— Chefk5

10

React 철학에 따르면 구성 요소는 소품을 변경할 수 없습니다. 그것들은 부모로부터 받아야하며 불변이어야합니다. 부모 만이 자녀의 소품을 바꿀 수 있습니다.

상태 대 소품 에 대한 좋은 설명

또한이 스레드를 읽으십시오 . react.js에서 props를 업데이트 할 수없는 이유는 무엇입니까?


이것은 또한 컨테이너가 redux store에서받는 소품을 수정할 수 없다는 것을 의미하지 않습니까?
— Tuomas Toivonen

3
컨테이너는 상점에서 직접 소품을받지 못하고 redux 상태 트리의 일부를 읽음으로써 공급됩니다 (혼란 ??). !! 혼란은 우리가 react-redux로 연결되는 마법의 기능에 대해 알지 못하기 때문입니다. connect 메소드의 소스 코드가 표시되면 기본적으로 storeState 특성을 가진 상태를 가지며 redux 저장소에 등록 된 상위 컴포넌트를 작성합니다. storeState가 변경되면 전체 다시 렌더링이 수행되고 수정 된 소품은 변경된 상태를 읽어 컨테이너에 공급됩니다. 이 답변을 질문 희망
— Sujan Thakare

좋은 설명, 고차 성분에 대한 생각은 무슨 일이 일어나고 있는지 이해하는 데 도움이됩니다
— Tuomas Toivonen

7

setState기능 을 사용해야 합니다. 그렇지 않으면 state는 forceUpdate 사용 방법에 관계없이 변경 사항을 저장하지 않습니다.

Container {
    handleEvent= () => { // use arrow function
        //this.props.foo.bar = 123
        //You should use setState to set value like this:
        this.setState({foo: {bar: 123}});
    };

    render() {
        return <Child bar={this.state.foo.bar} />
    }
    Child {
        render() {
            return <div>{this.props.bar}</div>
        }
    }
}

코드가 유효하지 않은 것 같습니다. 이 코드를 테스트 할 수 없습니다.


그렇지 <Child bar={this.state.foo.bar} />않습니까?
— Josh Broadhurst '

권리. 답변을 업데이트합니다. 그러나 내가 말했듯이 이것은 유효한 코드가 아닐 수도 있습니다. 단순히 질문에서 복사하십시오.
— JamesYin

5

functions및 에서 React 구성 요소를 작성할 때 useState.

const [drawerState, setDrawerState] = useState(false);

const toggleDrawer = () => {
      // attempting to trigger re-render
      setDrawerState(!drawerState);
};

이것은 수행 하지 작업

         <Drawer
            drawerState={drawerState}
            toggleDrawer={toggleDrawer}
         />

이 작업을 수행합니다 (추가 키)

         <Drawer
            drawerState={drawerState}
            key={drawerState}
            toggleDrawer={toggleDrawer}
         />

3

확인, 키 추가가 작동합니다. 나는 그 이유를 이해하고 시도하기 위해 문서를 살펴 보았습니다.

자식 구성 요소를 만들 때 React가 효율적이기를 원합니다. 다른 하위 요소와 동일한 경우 새 구성 요소를 렌더링하지 않으므로 페이지로드 속도가 빨라집니다.

키를 추가하면 React가 새 구성 요소를 렌더링하도록하여 새 구성 요소의 상태를 재설정합니다.

https://reactjs.org/docs/reconciliation.html#recursing-on-children


2

setState 함수를 사용하십시오. 그래서 당신은 할 수 있습니다

       this.setState({this.state.foo.bar:123}) 

핸들 이벤트 메소드 내부.

상태가 업데이트되면 변경 사항이 트리거되고 다시 렌더링됩니다.


1
this.setState ({foo.bar:123}) 맞아야합니까?
— 카리스 자야 산카

0

상태를 유지하지 않고 단순히 소품을 렌더링 한 다음 부모에서 호출하면 Child를 기능적 구성 요소로 만들어야합니다. 이에 대한 대안은 기능 구성 요소 (useState)와 함께 후크를 사용하여 상태 비 저장 구성 요소를 다시 렌더링 할 수 있다는 것입니다.

또한 propas가 불변이므로 propas를 변경해서는 안됩니다. 구성 요소의 상태를 유지하십시오.

Child = ({bar}) => (bar);

0

같은 문제가 발생했습니다. 나는 한 Tooltip수신 된 구성 요소 showTooltip나에 업데이트되었다, 소품을 Parent온 기반 구성 요소 if상태가 업데이트지고 한 Parent구성 요소 만 Tooltip구성 요소가 렌더링되지 않았습니다.

const Parent = () => {
   let showTooltip = false;
   if(....){ showTooltip = true; }
   return(
      <Tooltip showTooltip={showTooltip}></Tooltip>
   )
}

내가했던 실수 showTooltip는 let 으로 선언 하는 것입니다.

내가 잘못하고있는 것을 깨달았고 렌더링이 작동하는 방식의 원칙을 위반하고 있다는 것을 깨달았습니다.

const [showTooltip, setShowTooltip] =  React.useState<boolean>(false);

0

하위 컴포넌트에서 connect 메소드의 mapStateToProps에서 변경된 props를 정의하십시오.

function mapStateToProps(state) {
  return {
    chanelList: state.messaging.chanelList,
  };
}

export default connect(mapStateToProps)(ChannelItem);

필자의 경우 channelList의 채널이 업데이트되어 mapStateToProps에 chanelList를 추가했습니다.

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