bestsource

마운트/언마운트 사이에 React 컴포넌트 상태를 유지하는 방법

bestsource 2023. 2. 23. 22:58
반응형

마운트/언마운트 사이에 React 컴포넌트 상태를 유지하는 방법

구성 를 가지고 있습니다.<StatefulView>내부 상태를 유지합니다. 다른 요소가 .<App>를 .<StatefulView>렌더링 됩니다.

저는 계속 간직하고 .<StatefulView>"/" " "/"

는 그 를 포포의 인스턴스화할 수 있다고 생각했다.<App>렌더링/마운트 여부를 제어합니다.

var StatefulView = React.createClass({
  getInitialState: function() {
    return {
      count: 0
    }
  },
  inc: function() {
    this.setState({count: this.state.count+1})
  },
  render: function() {
    return (
        <div>
          <button onClick={this.inc}>inc</button>
          <div>count:{this.state.count}</div>
        </div>
    )
  }
});

var App = React.createClass({
  getInitialState: function() {
    return {
      show: true,
      component: <StatefulView/>
    }
  },
  toggle: function() {
    this.setState({show: !this.state.show})
  },
  render: function() {
    var content = this.state.show ? this.state.component : false
    return (
      <div>
        <button onClick={this.toggle}>toggle</button>
        {content}
      </div>
    )
  }
});

은 확실히 , 「 「 」 「 」 「 」는 기능하지 . 그리고 새로운 것은<StatefulView>을 사용하다

여기 JSFiddle이 있습니다.

같은 컴포넌트를 언마운트한 후에 다시 장착할 수 있는 방법이 있습니까?

마운트 해제 시 컴포넌트 자체의 상태를 유지할 수 없으므로 컴포넌트 이외의 저장처를 결정해야 합니다.

옵션은 다음과 같습니다.

  1. 부모 상태 반응: 부모 구성 요소가 마운트된 상태로 남아 있는 경우 해당 구성 요소가 상태의 소유자이거나 아래의 제어되지 않은 구성 요소에 초기 상태를 제공할 수 있습니다.구성 요소를 마운트 해제하기 전에 값을 다시 전달할 수 있습니다.React 컨텍스트를 사용하면 앱의 맨 위에 상태를 올릴 수 있습니다(: 미표시 참조).
  2. Outside of React: 예: use-local-storage-state.테스트 사이에 수동으로 상태를 리셋할 필요가 있는 경우가 있습니다.다른 옵션으로는 URL의 쿼리 매개 변수, MobX 또는 Redux 등의 상태 관리 라이브러리 등이 있습니다.

데이터가 React 외부에서 유지되는 쉬운 솔루션을 찾고 있습니다. 이 Hook이 유용할 수 있습니다.

const memoryState = {};

function useMemoryState(key, initialState) {
  const [state, setState] = useState(() => {
    const hasMemoryValue = Object.prototype.hasOwnProperty.call(memoryState, key);
    if (hasMemoryValue) {
      return memoryState[key]
    } else {
      return typeof initialState === 'function' ? initialState() : initialState;
    }
  });

  function onChange(nextState) {
    memoryState[key] = nextState;
    setState(nextState);
  }

  return [state, onChange];
}

사용방법:

const [todos, setTodos] = useMemoryState('todos', ['Buy milk']);

좋습니다. 여러 사람과 이야기를 나눈 결과 컴포넌트의 인스턴스를 저장할 방법이 없는 것으로 나타났습니다.따라서 다른 곳에 저장해야 합니다.

1) 상태를 저장할 수 있는 가장 확실한 장소는 상위 컴포넌트 내입니다.

UINavigationController와 같은 개체에서 뷰를 푸시 및 팝하려고 하기 때문에 이 옵션은 사용할 수 없습니다.

2) 플럭스 스토어 등 다른 장소나 글로벌 오브젝트에 상태를 저장할 수 있습니다.

또한 어떤 데이터가 어떤 Navigation Controller 등에 속하는지를 추적하는 것은 악몽이기 때문에 이 방법은 나에게 최적의 옵션이 아닙니다.

3) 상태를 저장하고 복원할 수 있는 가변 개체를 전달합니다.

React의 Github repo에 대한 다양한 이슈 티켓에서 코멘트를 하면서 발견한 제안입니다.이게 제가 가야 할 방법인 것 같아요. 왜냐하면 저는 변이 가능한 물체를 만들어서 소품으로 전달하고, 같은 변이 가능한 소품으로 같은 물체를 다시 렌더링할 수 있기 때문입니다.

사실 좀 더 일반화하기 위해 조금 수정했고, 가변 객체 대신 함수를 사용하고 있습니다.저는 이것이 더 정상적이라고 생각합니다. 불변의 데이터는 항상 저에게 선호됩니다.제가 하는 일은 다음과 같습니다.

function createInstance() {
  var func = null;
  return {
    save: function(f) {
      func = f;
    },
    restore: function(context) {
      func && func(context);
    }
  }
}

, 그럼 이제 ㅇㅇㅇㅇㅇㅇㅇㅇㅇ는요.getInitialState구성 요소의 새 인스턴스를 만드는 중입니다.

component: <StatefulView instance={createInstance()}/>

후 리 the the StatefulView.componentWillMount ★★★★★★★★★★★★★★★★★」componentWillUnmount.

componentWillMount: function() {
  this.props.instance.restore(this)
},
componentWillUnmount: function() {
  var state = this.state
  this.props.instance.save(function(ctx){
    ctx.setState(state)
  })
}

그리고 이것이 마지막입니다.나한테는 정말 잘 먹힌다.이제 컴포넌트를 인스턴스로 취급할 수 있습니다.

2019년 이후를 읽고 있는 분들을 위해 이미 많은 세부 사항이 다른 답변에서 제시되어 있습니다만, 여기서 강조하고 싶은 것이 몇 가지 있습니다.

  • 일부 저장소(Redux) 또는 컨텍스트에 상태를 저장하는 것이 가장 좋은 솔루션입니다.
  • 글로벌 변수에 저장하는 것은 한 번에 구성 요소의 인스턴스가 하나만 있는 경우에만 작동합니다.(각 인스턴스는 어떤 저장 상태가 자신의 상태인지 어떻게 알 수 있습니까?)
  • localStorage에 저장하는 것은 글로벌 변수와 동일한 경고이며, 브라우저 새로 고침 시 상태 복원에 대해 이야기하지 않기 때문에 아무런 이점이 없는 것 같습니다.

그럼 ㅇ, ㅇ, ㅇ, ㅇ, ㅇ, ㅇ, ㅇ, ㅇ, ㅇ, ㅇ, ㅇ, ㅇ, ㅇ, ㅇ, ㅇ.localStorage , 「」AsyncStorage[Respect Native] (네이티브 대응)

리액트 웹

componentWillUnmount() {
  localStorage.setItem('someSavedState', JSON.stringify(this.state))
}

그리고 그날 오후 또는 2초 후:

componentWillMount() {
  const rehydrate = JSON.parse(localStorage.getItem('someSavedState'))
  this.setState(rehydrate)
}

리액트 네이티브

import { AsyncStorage } from 'react-native'

async componentWillMount() {
  try {
    const result = await AsyncStorage.setItem('someSavedState', JSON.stringify(this.state))
    return result
  } catch (e) {
    return null
  }
}

그리고 그날 오후 또는 2초 후:

async componentWillMount() {
  try {
    const data = await AsyncStorage.getItem('someSavedState')
    const rehydrate = JSON.parse(data)
    return this.setState(rehydrate)
  } catch (e) {
    return null
  }
}

,도할 수 .Redux렌더링 시 데이터를 하위 구성요소로 전달합니다.하면 도움이 될 요.serializing 및 의 두 .createStore초기 상태를 재탈수하기 위한 함수입니다.

해 주세요.JSON.stringify()비용이 많이 드는 작업이기 때문에 키 누르기 등은 하지 말아 주세요.만약 당신이 염려가 있다면, 비난에 대해 조사하세요.

렌더링 간에 상태를 캐싱하는 쉬운 방법은 내보낸 모듈이 작업 중인 파일에 대해 폐쇄 형식으로 변환된다는 사실을 사용하는 것입니다.

「」의 useEffect후크 구성 요소 분리 시 발생하는 로직을 지정할 수 있습니다(즉, 모듈 수준에서 닫힌 변수 업데이트).Import하다 되는 않으면 Import)에 합니다.cachedState 렌더링됩니다).

var cachedState

export default () => {
  const [state, setState] = useState(cachedState || {})

  useEffect(() => {
    return () => cachedState = state
  })

  return (...)
}

파티에 늦었지만 당신이 레독스를 사용한다면.레독스 퍼시스턴트를 사용하면 그 행동을 거의 틀에서 벗어날 수 있을 것이다.추가만 하면 됩니다.autoRehydrate가게까지 가게가 듣고 있을 것이다.REHYDRATE컴포넌트의 이전 상태를 자동으로 복원하는 작업입니다(웹 스토리지에서).

저는 리액트 전문가가 아니지만, 특히 당신의 사건은 불변 물체 없이 아주 깔끔하게 해결할 수 있습니다.

var StatefulView = React.createClass({
  getInitialState: function() {
    return {
      count: 0
    }
  },
  inc: function() {
    this.setState({count: this.state.count+1})
  },
  render: function() {
      return !this.props.show ? null : (
        <div>
          <button onClick={this.inc}>inc</button>
          <div>count:{this.state.count}</div>
        </div>
    )

  }
});

var App = React.createClass({
  getInitialState: function() {
    return {
      show: true,
      component: StatefulView
    }
  },
  toggle: function() {
    this.setState({show: !this.state.show})
  },
  render: function() {
    return (
      <div>
        <button onClick={this.toggle}>toggle</button>
        <this.state.component show={this.state.show}/>
      </div>
    )
  }
});

ReactDOM.render(
  <App/>,
  document.getElementById('container')
);

jsfiddle에서 볼 수 있습니다.

바로 이 목적을 위해 간단한 NPM 패키지를 만들었습니다.다음 URL에서 찾을 수 있습니다.

https://www.npmjs.com/package/react-component-state-cache

사용법은 간단합니다.먼저 컴포넌트를 컴포넌트 트리 상단의 어딘가에 포함시킵니다.이러한 구성 요소는 다음과 같습니다.

import React from 'react'
import {ComponentStateCache} from 'react-component-state-cache'
import {Provider} from 'react-redux' // for example
import MyApp from './MyApp.js'

class AppWrapper extends React.Component {
    render() {
        return (
            <Provider store={this.store}>
                <ComponentStateCache>
                    <MyApp />
                </ComponentStateCache>
            </Provider>
        )
    }
}

그런 다음 다음과 같이 컴포넌트에서 사용할 수 있습니다.

import React from 'react'
import { withComponentStateCache } from 'react-component-state-cache'

class X extends React.Component {

    constructor(props) {
        super(props)

        this.state = {
            // anything, really.
        }
    }

    componentDidMount() {
        // Restore the component state as it was stored for key '35' in section 'lesson'
        //
        // You can choose 'section' and 'key' freely, of course.
        this.setState(this.props.componentstate.get('lesson', 35))
    }

    componentDidUnmount() {
         // store this state's component in section 'lesson' with key '35'
        this.props.componentstate.set('lesson', 35, this.state)
    }

}

export default withComponentStateCache(X)

바로 그겁니다.쉬워요.

상태를 유지하면서 마운트 해제 및 마운트를 수행할 수 있도록 하려면 다음 위치에 카운트를 저장해야 합니다.App소품들을 통해서 카운트 다운을 할 수 있습니다.

(이 처리를 할 때는, 내부에서의 토글 함수를 호출할 필요가 있습니다.App데이터를 데이터와 함께 사용할 수 있도록 변경하는 기능이 필요합니다).

당신의 바이올린을 기능하도록 수정하고 답변을 업데이트하겠습니다.

이 투고는 백엔드에서 추가 페이지마다 컴포넌트 상태를 장기간에 걸쳐 구축하는 방법을 찾고 있습니다.

나는 집요하고 환원제를 사용한다.그러나 이 상태에서는 컴포넌트에 로컬로 유지하려고 했습니다.작동하게 된 이유:useRef아무도 언급하지 않아서 질문의 중요한 부분을 놓칠 수 있다니 조금 놀랐습니다.그럼에도 불구하고ref반응하다

이렇게 하면 캐시를 오랜 시간에 걸쳐 구축할 수 있고 컴포넌트 업데이트(일명 재렌더)를 볼 수 있지만 컴포넌트와 관련된 이전 API 데이터를 "폐기"할 걱정은 없습니다.

  const cacheRef = useRef([]);
  const [page, setPage] = useState(() => 0);

  // this could be part of the `useEffect` hook instead as I have here
  const getMoreData = useCallback(
    async (pageProp, limit = 15) => {

      const newData = await getData({
        sources,
        page: pageProp,
        limit,
      });

      cacheRef.current = [...(cacheRef.current || []), ...newData];
      
    },
    [page, sources],
  );

  useEffect(() => {
    const atCacheCapacity = cacheRef.current.length >= MAX;
    if (!atCacheCapacity) {
      getMoreData(page + 1);
      setPage(page + 1);
    }
  }, [MAX, getMoreData, page]);

캐시의 크기가 커짐에 따라 변화하는 로컬 상태를 추적하여 컴포넌트를 재렌더링합니다.DOM의 참조 데이터를 컴포넌트의 로컬 상태로 복사하지 않습니다(길이 등).

이것은 스레드 오프너 시나리오에서는 충분하지 않지만, 이 스레드에 걸려 넘어지는 다른 사람에게는 다음과 같습니다.필요한 지속성 및 저장하려는 데이터의 복잡도에 따라 쿼리 매개 변수로도 충분할 수 있습니다.

를 들어,, Bool을 유지하다hideItems 변경 에 이 은 "창 크기 변경 작업"을 "창 크기 변경 작업"으로됩니다.my.example.com/myPage?hideItems=true페이지/컴포넌트 내에서 렌더링할 때 파라미터를 평가해야 합니다(예:NextJS 그럴 것이다.

const router = useRouter()
const hide = router.query.hideItems

제 경우 결제할 아이템을 선택하여 redux 스토어에 저장하는데, 컴포넌트가 아웃되지 않았을 때 상태를 새 목록으로 설정하고 싶습니다. 후에 는 '알아서'를 하고 있습니다. 이전 데이터를 보관하고 싶지 않습니다.useRef

const isPayment = useRef(false)

useEffect(() => { 

return () => {
  if(!isPayment.current){
     //if my handlePayment is called, 
     // I won't run my handle when component is unmout 
    Your action when component is unmout
  }
}
},[])

const handlePayment = () => {
  isPayment.current = true

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

언급URL : https://stackoverflow.com/questions/31352261/how-to-keep-react-component-state-between-mount-unmount

반응형