programing

반응 경고: 다른 구성 요소의 기능 본체 내부에서 구성 요소를 업데이트할 수 없습니다.

padding 2023. 3. 19. 19:52
반응형

반응 경고: 다른 구성 요소의 기능 본체 내부에서 구성 요소를 업데이트할 수 없습니다.

React에서 Class Components와 함께 Redux를 사용하고 있습니다.레독스 스토어에는 아래 두 가지 상태가 있습니다.

{ spinner: false, refresh: false }

[ Parent Components ](부모 컴포넌트)에는 이 상태를 변경하는 디스패치 기능이 있습니다.

class App extends React.Component {
  reloadHandler = () => {
    console.log("[App] reloadComponent");

    this.props.onShowSpinner();
    this.props.onRefresh();
  };

  render() {
    return <Child reloadApp={this.reloadHandler} />;
  }
}

Child Component에서 다음과 같이 부모 컴포넌트를 새로고침하려고 합니다.

class Child extends React.Component {
  static getDerivedStateFromProps(props, state) {
    if (somecondition) {
      // doing some redux store update
      props.reloadApp();
    }
  }

  render() {
    return <button />;
  }
}

아래와 같은 에러가 발생하고 있습니다.

경고: 다른 구성 요소의 기능 본체 내부에서 구성 요소를 업데이트할 수 없습니다.

이 경고를 제거하려면 어떻게 해야 합니까?내가 여기서 뭘 잘못하고 있는 거지?

나는 리액트 훅을 타고 레덕스 스토어에 가고 있었다. 수 없었다.useEffect반응:

export const useOrderbookSubscription = marketId => {
  const { data, error, loading } = useSubscription(ORDERBOOK_SUBSCRIPTION, {
    variables: {
      marketId,
    },
  })

  const formattedData = useMemo(() => {
    // DISPATCHING HERE CAUSED THE WARNING
  }, [data])

  // DISPATCHING HERE CAUSED THE WARNING TOO

  // Note: Dispatching to the store has to be done in a useEffect so that React
  // can sync the update with the render cycle otherwise it causes the message:
  // `Warning: Cannot update a component from inside the function body of a different component.`
  useEffect(() => {
    orderbookStore.dispatch(setOrderbookData(formattedData))
  }, [formattedData])

  return { data: formattedData, error, loading }
}

다음과 같은 조건이 충족되면 코드가 부모 컴포넌트의 함수를 호출하는 경우:

const ListOfUsersComponent = ({ handleNoUsersLoaded }) => {
    const { data, loading, error } = useQuery(QUERY);

    if (data && data.users.length === 0) {
        return handleNoUsersLoaded();
    }

    return (
        <div>
            <p>Users are loaded.</p>
        </div>
    );
};

도 이 조건을 '아로해 보세요.useEffect:

const ListOfUsersComponent = ({ handleNoUsersLoaded }) => {
    const { data, loading, error } = useQuery(QUERY);

    useEffect(() => {
        if (data && data.users.length === 0) {
            return handleNoUsersLoaded();
        }
    }, [data, handleNoUsersLoaded]);

    return (
        <div>
            <p>Users are loaded.</p>
        </div>
    );
};

최신 빌드인 것 같습니다.React@16.13.x자세한 내용은 이쪽에서 확인하실 수 있습니다.이 명령어는 다음과 같이 명시되어 있습니다.setState다른 컴포넌트로부터 다른 컴포넌트로부터 다른 컴포넌트를 취득합니다.

다음 문서를 참조해 주세요.

렌더 중에 setState를 호출하는 것은 지원되지만 동일한 컴포넌트에 대해서만 지원됩니다.다른 컴포넌트의 렌더 중에 setState를 호출하면 다음과 같은 경고가 표시됩니다.
Warning: Cannot update a component from inside the function body of a different component.
이 경고는 의도하지 않은 상태 변경으로 인한 응용 프로그램 버그를 찾는 데 도움이 됩니다.드물게 렌더링 결과 다른 컴포넌트의 상태를 의도적으로 변경하려는 경우 setState 호출을 useEffect로 랩할 수 있습니다.


본론으로 들어갑시다.

것 같아요.getDerivedStateFromProps자 컴포넌트 본체에 장착한다.츠요시 다음 '하다'를 요.onClick 중 Child 입니다.<button/>.

class Child extends React.Component {
  constructor(props){
    super(props);
    this.updateState = this.updateState.bind(this);
  }
  updateState() { // call this onClick to trigger the update
    if (somecondition) {
      // doing some redux store update
      this.props.reloadApp();
    }
  }

  render() {
    return <button onClick={this.updateState} />;
  }
}

오류는 같지만 시나리오는 다릅니다.

tl;dr 래핑 상태 업데이트setTimeout칩니니다

이 시나리오로 인해 IMO가 유효한 사용 사례인 문제가 발생하였습니다.

const [someState, setSomeState] = useState(someValue);
const doUpdate = useRef((someNewValue) => {
  setSomeState(someNewValue);
}).current;
return (
  <SomeComponent onSomeUpdate={doUpdate} />
);

고치다

const [someState, setSomeState] = useState(someValue);
const doUpdate = useRef((someNewValue) => {
  setTimeout(() => {
   setSomeState(someNewValue);
  }, 0);
}).current;
return (
  <SomeComponent onSomeUpdate={doUpdate} />
);

.()=>{}

onDismiss={()=>{/*do something*/}}

라고 생각했다.onDismiss={/*do something*/}

리액션과 리액션을 네이티브로 업그레이드한 후에도 같은 문제가 발생했는데, 그냥 소품이나 내비게이션을 넣어주세요.setOptions를 in useEffect로 설정합니다.만약 누군가가 내가 가지고 있던 것과 같은 문제에 직면해 있다면, 나는 단지 그에게 당신의 상태를 바꾸거나 안에 있는 어떤 것을 사용하라고 제안하고 싶다.효과

에 코멘트를 만, 이는 해결할 수 있습니다는, 「」를 동시에 때문에 합니다.「 」 「 」 「 」 「 」 「 」 「 」 「 」 「 」 「 」 。 : 」 。reloadAppcomponentDidMount().

import React from "react";

export default class App extends React.Component {
  reloadHandler = () => {
    console.log("[App] reloadComponent");

    // this.props.onShowSpinner();
    // this.props.onRefresh();
  };

  render() {
    return <Child reloadApp={this.reloadHandler} />;
  }
}

class Child extends React.Component {
  static getDerivedStateFromProps(props, state) {
    // if (somecondition) {
    // doing some redux store update
    props.reloadApp();
    // }
  }

  componentDidMount(props) {
    if (props) {
      props.reloadApp();
    }
  }

  render() {
    return <h1>This is a child.</h1>;
  }
}

swiper를 고정하기 위해 redux를 사용했을 때 이 오류가 발생하였습니다.반응-원어민-스위퍼를 사용한 지수

changeSwiperIndex를 타임아웃으로 수정

화면 간 네비게이션을 호출하면서 리액트 네이티브 프로젝트를 위해 다음과 같이 받았습니다.

    Warning: Cannot update a component from inside the function body of a different component.

Touchable Opacity를 사용하고 있기 때문이라고 생각했습니다.이는 Pressable, Button 또는 Touchable Opacity 사용에 관한 문제가 아닙니다.에러 메세지가 표시되었을 때, 홈 화면에서 Chat Room 화면을 호출하는 코드는 다음과 같습니다.

    const HomeScreen = ({navigation}) => { 
    return (<View> <Button title = {'Chats'} onPress = { navigation.navigate('ChatRoom')} <View>) } 

그 결과 코드가 경고를 표시했기 때문에 이전 홈스크린으로 돌아가서 버튼을 다시 사용하여 채팅룸으로 이동할 수 없었습니다.이에 대한 해결책은 인라인 익명 함수로 onPress를 실행하는 것이었습니다.

    onPress{ () => navigation.navigate('ChatRoom')}

앞의 것이 아니라

    onPress{ navigation.navigate('ChatRoom')}

이제 예상대로 홈에서 채팅룸으로 이동한 후 재사용 가능한 버튼으로 다시 돌아갈 수 있습니다.

PS: Stack Overflow 사상 첫 번째 답변입니다.여전히 공동체 예절을 배우고 있다.더 잘 대답할 수 있는 방법을 알려주세요.고맙습니다

자 컴포넌트에서 소품으로 전달된 함수를 자동으로 호출하는 경우 클래스 컴포넌트의 경우 componentDidMount 라이프 사이클 메서드, 기능 컴포넌트의 경우 useEffect 훅이 최적의 장소입니다.

사용자가 다른 컴포넌트 내의 목록 내의 항목을 제한할 수 있는 텍스트박스가 몇 개 있는 필터 컴포넌트를 쓰는 데 이 문제가 발생했습니다.저는 Redux 상태에서 필터링된 아이템을 추적하고 있었습니다.이 솔루션은 기본적으로 @Rajnikant의 솔루션이며 샘플코드가 포함되어 있습니다.

나는 다음과 같은 이유로 경고를 받았다.해 주세요.props.setFilteredItems렌더링 함수에 있습니다.

import {setFilteredItems} from './myActions';
const myFilters = props => {
  const [nameFilter, setNameFilter] = useState('');
  const [cityFilter, setCityFilter] = useState('');

  const filterName = record => record.name.startsWith(nameFilter);
  const filterCity = record => record.city.startsWith(cityFilter);

  const selectedRecords = props.records.filter(rec => filterName(rec) && filterCity(rec));
  props.setFilteredItems(selectedRecords); //  <-- Danger! Updates Redux during a render!

  return <div>
    <input type="text" value={nameFilter} onChange={e => setNameFilter(e.target.value)} />
    <input type="text" value={cityFilter} onChange={e => setCityFilter(e.target.value)} />
  </div>
};

const mapStateToProps = state => ({
  records: state.stuff.items,
  filteredItems: state.stuff.filteredItems
});
const mapDispatchToProps = { setFilteredItems };
export default connect(mapStateToProps, mapDispatchToProps)(myFilters);

했을 때16.12.0브라우저 콘솔에서 이 스레드의 항목에 나열된 경고를 받았습니다.트레이스에 해, 의 「」입니다.props.setFilteredItems호출할 수 있습니다. 필터 를 '필터 호출'에했습니다.useEffect이하와 같습니다.

import {setFilteredItems} from './myActions';
const myFilters = props => {
  const [nameFilter, setNameFilter] = useState('');
  const [cityFilter, setCityFilter] = useState('');

  useEffect(() => {
    const filterName = record => record.name.startsWith(nameFilter);
    const filterCity = record => record.city.startsWith(cityFilter);

    const selectedRecords = props.records.filter(rec => filterName(rec) && filterCity(rec));
    props.setFilteredItems(selectedRecords); //  <-- OK now; effect runs outside of render.
  }, [nameFilter, cityFilter]);

  return <div>
    <input type="text" value={nameFilter} onChange={e => setNameFilter(e.target.value)} />
    <input type="text" value={cityFilter} onChange={e => setCityFilter(e.target.value)} />
  </div>
};

const mapStateToProps = state => ({
  records: state.stuff.items,
  filteredItems: state.stuff.filteredItems
});
const mapDispatchToProps = { setFilteredItems };
export default connect(mapStateToProps, mapDispatchToProps)(myFilters);

처음 추가했을 때useEffect모든 사건 이후로 난 발끈했어요useEffect상태 변화를 일으켰습니다.필터 필드 자체가 변경될 때만 효과가 실행되도록 건너뛰기 효과 배열을 추가해야 했습니다.

아래 동영상을 볼 것을 제안합니다.OP 질문의 경고에서 알 수 있듯이 다른 형제자녀(자녀 1)가 부모에게 콜백한 결과 부모(자녀 2)가 한 자녀(자녀 2)의 속성을 업데이트하려고 하는 변경 감지 문제가 있습니다.제 경우, Child 2가 Passed in Parent 콜백을 시기상조 또는 잘못 호출하여 경고를 발생시켰습니다.

이 연동의 워크플로우는 옵션일 뿐입니다.개인적으로 공유 Redux 스토어를 통한 컴포넌트 간 데이터 교환 및 업데이트를 선호합니다.하지만 때로는 과잉 살상일 수도 있습니다.이 비디오는 아이들이 '멍청'하고 소품 맨드 콜백을 통해서만 대화하는 깨끗한 대안을 제시한다.

또한 콜백이 버튼 클릭과 같이 Child 1 '이벤트'에서 호출된 경우에는 Child 1이 업데이트되었기 때문에 작동합니다.타임아웃, useEffects 등이 불필요합니다.이 좁은 시나리오에서는 UseState로 충분합니다.

다음은 링크입니다(Masoud님 감사합니다).

https://www.youtube.com/watch?v=Qf68sssXPtM

리액트 네이티브에서는 핫 새로고침을 사용하여 코드에서 직접 상태를 변경하면 이 오류가 발생하지만 버튼을 사용하여 상태를 변경하면 오류가 사라집니다.

단, useEffect 콘텐츠를 에 정리하는 방법:

setTimeout(() => {
    //....
}, 0);

핫 새로고침에도 효과가 있었지만, 아무 이유 없이 set Timeout을 하고 싶지 않기 때문에 삭제하고 코드로 변경해도 문제없다는 것을 알게 되었습니다.

여러 개의 하위 구성 요소에서 동시에 상태를 업데이트하고 있어서 예기치 않은 동작이 발생했습니다.교환useState와 함께useRef훅이 통했어

내가 소품을 부를 때 setTimeout을 사용해봐setTimeout이 없는 showNotification은 이 오류가 나타납니다.라이프 서클에서 모든 inTime이 실행되고 UI가 갱신되지 않을 수 있습니다.

const showNotifyTimeout = setTimeout(() => {
          this.props.showNotification();
          clearTimeout(showNotifyTimeout);
        }, 100);

언급URL : https://stackoverflow.com/questions/60526786/react-warning-cannot-update-a-component-from-inside-the-function-body-of-a-diff

반응형