ReactJS 상태 대 소품
이것은 대답 할 수있는 것과 의견이있는 것 사이의 선을 밟을 수도 있지만 복잡성이 커지고 방향을 사용할 수있을 때 ReactJS 구성 요소를 구성하는 방법에 대해 앞뒤로 가고 있습니다.
AngularJS에서 온 모델을 구성 요소에 속성으로 전달하고 구성 요소가 모델을 직접 수정하도록하고 싶습니다. 아니면 모델을 다양한 state
속성 으로 분할하고 업스트림으로 다시 보낼 때 다시 컴파일해야합니까? ReactJS 방식은 무엇입니까?
블로그 게시물 편집기를 예로 들어 보겠습니다. 모델을 수정하려고하면 다음과 같이 나타납니다.
var PostEditor = React.createClass({
updateText: function(e) {
var text = e.target.value;
this.props.post.text = text;
this.forceUpdate();
},
render: function() {
return (
<input value={this.props.post.text} onChange={this.updateText}/>
<button onClick={this.props.post.save}/>Save</button>
);
}
});
어느 것이 잘못된 것 같습니다.
다음 과 같이 저장하기 전에 text
모델 속성 을 만들고 모델 state
로 다시 컴파일하는 것이 더 반응적인 방법입니까?
var PostEditor = React.createClass({
getInitialState: function() {
return {
text: ""
};
},
componentWillMount: function() {
this.setState({
text: this.props.post.text
});
},
updateText: function(e) {
this.setState({
text: e.target.value
});
},
savePost: function() {
this.props.post.text = this.state.text;
this.props.post.save();
},
render: function() {
return (
<input value={this.state.text} onChange={this.updateText}/>
<button onClick={this.savePost}/>Save</button>
);
}
});
에 대한 호출은 필요하지 않지만 this.forceUpdate()
모델이 커짐에 따라 (게시자, 주제, 태그, 댓글, 등급 등의 게시물이있을 수 있음) 구성 요소가 실제로 복잡해지기 시작합니다.
두 번째 방법은 더 비슷합니다. React는 값 과 앱을 통해 흐르는 방식에 관심이있는 모델은 신경 쓰지 않습니다 . 이상적으로는 포스트 모델이 루트의 단일 구성 요소에 저장됩니다. 그런 다음 각각 모델의 일부를 소비하는 하위 구성 요소를 만듭니다.
데이터를 수정해야하는 자식에게 콜백을 전달하고 자식 구성 요소에서 호출 할 수 있습니다.
React가 변경 사항을 선택할 수 없으므로 this.props 또는 this.state를 직접 수정하는 것은 좋은 생각이 아닙니다. React가 포스트 소품을 얕게 비교하여 변경되었는지 확인하기 때문입니다.
이 jsfiddle 을 사용하여 데이터가 외부에서 내부 구성 요소로 어떻게 흐르는 지 보여줍니다.
이 handleClick
방법은 상태를 적절하게 업데이트하는 3 가지 방법을 보여줍니다.
var Outer = React.createClass({
getInitialState: function() {
return {data: {value: 'at first, it works'}};
},
handleClick: function () {
// 1. This doesn't work, render is not triggered.
// Never set state directly because the updated values
// can still be read, which can lead to unexpected behavior.
this.state.data.value = 'but React will never know!';
// 2. This works, because we use setState
var newData = {value: 'it works 2'};
this.setState({data: newData});
// 3. Alternatively you can use React's immutability helpers
// to update more complex models.
// Read more: http://facebook.github.io/react/docs/update.html
var newState = React.addons.update(this.state, {
data: {value: {$set: 'it works'}}
});
this.setState(newState);
},
render: function() {
return <Inner data={this.state.data} handleClick={this.handleClick} />;
}
});
2016 업데이트 : React가 변경되었으며 "props vs state"설명이 매우 간단 해졌습니다. 컴포넌트가 데이터를 변경해야하는 경우 상태를 유지하고 그렇지 않으면 props를 작성하십시오. 소품은 이제 읽기 전용 이기 때문 입니다.
소품과 상태의 정확한 차이점은 무엇입니까?
여기서 좋은 설명을 찾을 수 있습니다 (풀 버전)
반응 문서에서
props are immutable: they are passed from the parent and are "owned" by the parent. To implement interactions, we introduce mutable state to the component. this.state is private to the component and can be changed by calling this.setState(). When the state is updated, the component re-renders itself.
From TrySpace: when props (or state) are updated (via setProps/setState or parent) the component re-renders as well.
A reading from Thinking in React:
Let's go through each one and figure out which one is state. Simply ask three questions about each piece of data:
- Is it passed in from a parent via props? If so, it probably isn't state.
Does it change over time? If not, it probably isn't state.
Can you compute it based on any other state or props in your component? If so, it's not state.
I'm not sure if I'm answering your question, but I've found that, especially in a large/growing application, the Container/Component pattern works incredibly well.
Essentially you have two React components:
- a "pure" display component, which deals with styling and DOM interaction;
- a container component, which deals with accessing/saving external data, managing state, and rendering the display component.
Example
N.B. This example is a probably too simple to illustrate the benefits of this pattern, as it is quite verbose for such a straightforward case.
/**
* Container Component
*
* - Manages component state
* - Does plumbing of data fetching/saving
*/
var PostEditorContainer = React.createClass({
getInitialState: function() {
return {
text: ""
};
},
componentWillMount: function() {
this.setState({
text: getPostText()
});
},
updateText: function(text) {
this.setState({
text: text
});
},
savePost: function() {
savePostText(this.state.text);
},
render: function() {
return (
<PostEditor
text={this.state.text}
onChange={this.updateText.bind(this)}
onSave={this.savePost.bind(this)}
/>
);
}
});
/**
* Pure Display Component
*
* - Calculates styling based on passed properties
* - Often just a render method
* - Uses methods passed in from container to announce changes
*/
var PostEditor = React.createClass({
render: function() {
return (
<div>
<input type="text" value={this.props.text} onChange={this.props.onChange} />
<button type="button" onClick={this.props.onSave} />
</div>
);
}
});
Benefits
By keeping display logic and data/state management separate, you have a re-usable display component which:
- can easily be iterated with different sets of props using something like react-component-playground
- can be wrapped with a different container for different behavior (or combine with other components to build larger parts of your application
You also have a container component which deals with all external communication. This should make it easier to be flexible about the way you access your data if you make any serious changes later on*.
This pattern also makes writing and implementing unit tests a lot more straightforward.
Having iterated a large React app a few times, I've found that this pattern keeps things relatively painless, especially when you have larger components with calculated styles or complicated DOM interactions.
*Read up on the flux pattern, and take a look at
Marty.js, which largely inspired this answer (and I have been using a lot lately)
Redux (and react-redux), which implement this pattern extremely well.
Note for those reading this in 2018 or later:
React has evolved quite a bit since this answer was written, especially with the introduction of Hooks. However, the underlying state management logic from this example remains the same, and more importantly, the benefits that you get from keeping your state and presentation logic separate still apply in the same ways.
I think you're using an anti-pattern which Facebook has already explained at this link
Here's thing you're finding:
React.createClass({
getInitialState: function() {
return { value: { foo: 'bar' } };
},
onClick: function() {
var value = this.state.value;
value.foo += 'bar'; // ANTI-PATTERN!
this.setState({ value: value });
},
render: function() {
return (
<div>
<InnerComponent value={this.state.value} />
<a onClick={this.onClick}>Click me</a>
</div>
);
}
});
The first time the inner component gets rendered, it will have { foo: 'bar' } as the value prop. If the user clicks on the anchor, the parent component's state will get updated to { value: { foo: 'barbar' } }, triggering the re-rendering process of the inner component, which will receive { foo: 'barbar' } as the new value for the prop.
The problem is that since the parent and inner components share a reference to the same object, when the object gets mutated on line 2 of the onClick function, the prop the inner component had will change. So, when the re-rendering process starts, and shouldComponentUpdate gets invoked, this.props.value.foo will be equal to nextProps.value.foo, because in fact, this.props.value references the same object as nextProps.value.
Consequently, since we'll miss the change on the prop and short circuit the re-rendering process, the UI won't get updated from 'bar' to 'barbar'
참고URL : https://stackoverflow.com/questions/23481061/reactjs-state-vs-prop
'Programing' 카테고리의 다른 글
Eclipse : 동일한 편집기 탭을 사용하여 여러 번 검색 한 파일 (0) | 2020.07.14 |
---|---|
MS SQL Server Management Studio에서 트랜잭션 작업을 수행하는 가장 좋은 방법 (0) | 2020.07.14 |
vim의 디스크에서 버퍼의 모든 파일을 새로 고칩니다. (0) | 2020.07.14 |
CSS 마진 테러; (0) | 2020.07.14 |
Xcode에서 서명 신원 문제를 해결할 수 없습니다 (0) | 2020.07.14 |