setState를 호출하지 않고 React 컴포넌트를 강제로 다시 렌더링 할 수 있습니까?
변경 사항을 듣고 싶은 외부 (구성 요소에 대한) 관찰 가능한 객체가 있습니다. 개체가 업데이트되면 변경 이벤트가 발생하고 변경 사항이 감지되면 구성 요소를 다시 렌더링하고 싶습니다.
최상위 수준 React.render
에서는 가능했지만 구성 요소 내에서는 작동하지 않습니다 ( render
메서드가 개체를 반환하기 때문에 의미가 있음 ).
다음은 코드 예입니다.
export default class MyComponent extends React.Component {
handleButtonClick() {
this.render();
}
render() {
return (
<div>
{Math.random()}
<button onClick={this.handleButtonClick.bind(this)}>
Click me
</button>
</div>
)
}
}
버튼을 클릭하면 내부적으로를 호출 this.render()
하지만 실제로 렌더링이 발생하는 {Math.random()}
것은 아닙니다 (에서 만든 텍스트 가 변경되지 않기 때문에 실제로이 작업을 볼 수 있습니다). 그러나 this.setState()
대신 단순히 호출 this.render()
하면 제대로 작동합니다.
그래서 내 질문은 : React 구성 요소 가 다시 렌더링하기 위해 상태를 가져야합니까? 상태를 변경하지 않고 요청시 구성 요소를 강제로 업데이트하는 방법이 있습니까?
구성 요소 this.forceUpdate()
에서을 호출 하여 강제로 다시 렌더링 할 수 있습니다 .
문서 : https://facebook.github.io/react/docs/component-api.html
forceUpdate
React 사고 방식에서 벗어나기 때문에 피해야합니다. React 문서는 언제 forceUpdate
사용될 수 있는지에 대한 예를 인용합니다 .
기본적으로 구성 요소의 상태 또는 소품이 변경되면 구성 요소가 다시 렌더링됩니다. 그러나 이러한 변경이 암시 적으로 변경되거나 (예 : 객체 자체를 변경하지 않고 객체 내의 깊은 데이터가 변경되는 경우) 또는 render () 메서드가 다른 데이터에 의존하는 경우 React를 호출하여 render ()를 다시 실행해야한다고 알릴 수 있습니다. 강제 업데이트().
그러나 깊이 중첩 된 객체라도 forceUpdate
불필요 하다는 아이디어를 제안하고 싶습니다 . 변경 불가능한 데이터 소스를 사용하면 변경 사항을 추적하는 비용이 저렴 해집니다. 변경은 항상 새 객체를 생성하므로 객체에 대한 참조가 변경되었는지 확인하기 만하면됩니다. Immutable JS 라이브러리를 사용 하여 앱에 변경 불가능한 데이터 개체를 구현할 수 있습니다.
일반적으로 forceUpdate ()의 모든 사용을 피하고 render ()의 this.props 및 this.state에서만 읽어야합니다. 이를 통해 구성 요소를 "순수"하고 응용 프로그램을 훨씬 간단하고 효율적으로 만듭니다. 강제 업데이트()
다시 렌더링하려는 요소의 키를 변경하면 작동합니다. 상태를 통해 요소에 키 소품을 설정 한 다음 새 키를 갖도록 설정 상태를 업데이트하려는 경우.
<Element key={this.state.key} />
그런 다음 변경이 발생하고 키를 재설정합니다.
this.setState({ key: Math.random() });
이것이 키가 변경되는 요소를 대체한다는 점에 유의하고 싶습니다. 이것이 유용 할 수있는 예는 이미지 업로드 후 재설정하려는 파일 입력 필드가있는 경우입니다.
OP의 질문에 대한 진정한 대답 forceUpdate()
은이 솔루션이 다른 상황에서 도움이된다는 것입니다. 또한 자신이 사용하는 것을 발견 forceUpdate
하면 코드를 검토하고 다른 작업을 수행 할 수있는 방법이 있는지 확인하는 것이 좋습니다.
참고 1-9-2019 :
위 (키 변경)는 요소를 완전히 대체합니다. 변경 사항을 적용하기 위해 키를 업데이트하는 경우 코드의 다른 부분에 문제가있을 수 있습니다. Math.random()
in 키를 사용하면 렌더링 할 때마다 요소가 다시 생성됩니다. react가 키를 사용하여 물건을 다시 렌더링하는 가장 좋은 방법을 결정하므로 이와 같은 키를 업데이트하는 것은 권장하지 않습니다.
실제로에서 추가 로직이 구현 되거나 단순히를 반환 하는 경우 다시 렌더링을 트리거 하지 않을 수 forceUpdate()
있는 유일한 올바른 솔루션 입니다.setState()
shouldComponentUpdate()
false
강제 업데이트()
호출
forceUpdate()
하면render()
을 건너 뛰고 구성 요소에서 호출 됩니다shouldComponentUpdate()
. 더...
setState ()
setState()
조건부 렌더링 논리가에서 구현되지 않는 한 항상 다시 렌더링을 트리거합니다shouldComponentUpdate()
. 더...
forceUpdate()
컴포넌트 내에서 다음과 같이 호출 할 수 있습니다.
this.forceUpdate()
나는 피할 forceUpdate
다음을 수행하여
잘못된 방법 : 인덱스를 키로 사용하지 마십시오.
this.state.rows.map((item, index) =>
<MyComponent cell={item} key={index} />
)
올바른 방법 : 데이터 ID를 키로 사용하십시오.
this.state.rows.map((item) =>
<MyComponent item={item} key={item.id} />
)
따라서 이러한 코드 개선을 수행하면 구성 요소가 고유 하고 자연스럽게 렌더링됩니다.
관계 (부모-자식)로 묶이지 않는 두 개의 React 구성 요소가 통신하기를 원할 때 Flux 또는 유사한 아키텍처 를 사용하는 것이 좋습니다 .
당신이 원하는 것은 모델과 그 인터페이스를 보유하고있는
관찰 가능한 컴포넌트
저장소의 변경을 수신
하고에서와 같이 렌더가 변경되도록하는 데이터를 저장하는 것 state
입니다 MyComponent
. 저장소에서 새 데이터를 푸시하면 구성 요소의 상태가 변경되어 자동으로 렌더링이 트리거됩니다.
일반적으로 forceUpdate()
. 문서에서 :
일반적으로 forceUpdate ()의 모든 사용을 피하고 render ()의 this.props 및 this.state에서만 읽어야합니다. 이것은 당신의 응용 프로그램을 훨씬 더 간단하고 효율적으로 만듭니다.
HOC를 사용하여 저장소 변경 사항 바인딩
은 Using HOC (고차 구성 요소) 패턴을 , 당신은 당신의 구성 요소를 반응 자동 업데이트 상점에 변화를 포장 할 수 있습니다. 이것은 프레임 워크가없는 매우 가벼운 접근 방식입니다.
withStores HOC 핸들 스토어 업데이트
import React, { Component } from 'react'
export default function(/* store1, store2, store3... */) {
const storeArgs = Array.prototype.slice.call(arguments)
return function(WrappedComponent) {
return class WithStore extends Component {
constructor(props) {
super(props)
this.state = {
lastUpdated: Date.now()
}
this.stores = storeArgs
}
_onChange = () => {
this.setState({ lastUpdated: Date.now() })
}
componentWillMount = () => {
this.stores && this.stores.forEach(store => {
// each store has a common change event to subscribe to
store.on('change', this._onChange)
})
}
componentWillUnmount = () => {
this.stores && this.stores.forEach(store => {
store.off('change', this._onChange)
})
}
render() {
return <WrappedComponent
lastUpdated={this.state.lastUpdated}
{...this.props} />
}
}
}
}
사용하는 방법
import React, { Component } from 'react'
import { View, Text, Button } from 'react-native'
import withStores from './withStores'
import userStore from './stores/users'
class MyView {
_increaseUserCount = () => {
userStore.setState({ userCount: userStore.state.count + 1 })
}
render() {
return (
<View>
<Text>User count: {userStore.state.count}</Text>
<Button
title="Increase User Count"
onPress={this._increaseUserCount}
/>
</View>
)
}
}
export default withStores(userStore)(MyView)
간단한 저장소 클래스 예
var ee = require('event-emitter')
export default class Store {
constructor() {
this._state = {}
this._eventEmitter = ee({})
}
get state() {
return this._state
}
setState(newState) {
this._state = {...this._state, ...newState}
this._eventEmitter.emit('change')
}
on(ev, fn) {
this._eventEmitter.on(ev, fn)
}
off(ev, fn) {
this._eventEmitter.off(ev, fn)
}
}
인스턴스 를 싱글 톤으로 저장
import Store from './Store'
const myStore = new Store()
export default myStore
이것은 실제로 구성 요소 트리의 깊이가 낮은 소규모 프로젝트 를 위한 것 입니다. 그 이유는 더 큰 구성 요소 트리에 이것을 사용하면 상점에 대해 어떤 부분을 업데이트할지 선택하지 않고 상점 자체가 업데이트를 트리거하기 때문입니다.
You will be ok if you split up your stores in a more granular fashion but then again, this is why redux is good as it can be both granular as needed and only requires a single store but also has disproportionate boilerplate on a smaller project.
So I guess my question is: do React components need to have state in order to rerender? Is there a way to force the component to update on demand without changing the state?
The other answers have tried to illustrate how you could, but the point is that you shouldn't. Even the hacky solution of changing the key misses the point. The power of React is giving up control of manually managing when something should render, and instead just concerning yourself with how something should map on inputs. Then supply stream of inputs.
If you need to manually force re-render, you're almost certainly not doing something right.
You could do it a couple of ways:
1. Use the forceUpdate()
method:
There are some glitches that may happen when using the forceUpdate()
method. One example is that it ignores the shouldComponentUpdate()
method and will re-render the view regardless of whether shouldComponentUpdate()
returns false. Because of this using forceUpdate() should be avoided when at all possible.
2. Passing this.state to the setState()
method
The following line of code overcomes the problem with the previous example:
this.setState(this.state);
Really all this is doing is overwriting the current state with the current state which triggers a re-rendering. This still isn't necessarily the best way to do things, but it does overcome some of the glitches you might encounter using the forceUpdate() method.
There are a few ways to rerender your component:
The simplest solution is to use forceUpdate() method:
this.forceUpdate()
One more solution is to create not used key in the state(nonUsedKey) and call setState function with update of this nonUsedKey:
this.setState({ nonUsedKey: Date.now() } );
Or rewrite all current state:
this.setState(this.state);
Props changing also provides component rerender.
We can use this.forceUpdate() as below.
class MyComponent extends React.Component {
handleButtonClick = ()=>{
this.forceUpdate();
}
render() {
return (
<div>
{Math.random()}
<button onClick={this.handleButtonClick}>
Click me
</button>
</div>
)
}
}
ReactDOM.render(<MyComponent /> , mountNode);
The Element 'Math.random' part in the DOM only gets updated even if you use the setState to re-render the component.
All the answers here are correct supplementing the question for understanding..as we know to re-render a component with out using setState({}) is by using the forceUpdate().
The above code runs with setState as below.
class MyComponent extends React.Component {
handleButtonClick = ()=>{
this.setState({ });
}
render() {
return (
<div>
{Math.random()}
<button onClick={this.handleButtonClick}>
Click me
</button>
</div>
)
}
}
ReactDOM.render(<MyComponent /> , mountNode);
Just another reply to back-up the accepted answer :-)
React discourages the use of forceUpdate()
because they generally have a very "this is the only way of doing it" approach toward functional programming. This is fine in many cases, but many React developers come with an OO-background, and with that approach, it's perfectly OK to listen to an observable object.
And if you do, you probably know you MUST re-render when the observable "fires", and as so, you SHOULD use forceUpdate()
and it's actually a plus that shouldComponentUpdate()
is NOT involved here.
Tools like MobX, that takes an OO-approach, is actually doing this underneath the surface (actually MobX calls render()
directly)
I have found it best to avoid forceUpdate(). One way to force re-render is to add dependency of render() on a temporary external variable and change the value of that variable as and when needed.
Here's a code example:
class Example extends Component{
constructor(props){
this.state = {temp:0};
this.forceChange = this.forceChange.bind(this);
}
forceChange(){
this.setState(prevState => ({
temp: prevState.temp++
}));
}
render(){
return(
<div>{this.state.temp &&
<div>
... add code here ...
</div>}
</div>
)
}
}
Call this.forceChange() when you need to force re-render.
ES6 - I am including an example, which was helpful for me:
In a "short if statement" you can pass empty function like this:
isReady ? ()=>{} : onClick
This seems to be the shortest approach.
()=>{}
forceUpdate();
method will work but it is advisable to use setState();
In order to accomplish what you are describing please try this.forceUpdate().
Another way is calling setState
, AND preserve state:
this.setState(prevState=>({...prevState}));
forceUpdate(), but every time I've ever heard someone talk about it, it's been followed up with you should never use this.
You can use forceUpdate() for more details check (forceUpdate()).
'program tip' 카테고리의 다른 글
JSON과 유사한 형식으로 원형 구조를 인쇄하려면 어떻게해야합니까? (0) | 2020.10.03 |
---|---|
Bash에서 단일 명령으로 셸 변수에 기본값 할당 (0) | 2020.10.03 |
React Native와 React의 차이점은 무엇입니까? (0) | 2020.10.03 |
데이터베이스에 대한 ** 모든 ** 권한 부여 (0) | 2020.10.03 |
"피어 별 연결 재설정"이란 무엇을 의미합니까? (0) | 2020.10.03 |