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


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.