Redux 상태가 변경되었습니다. React가 재렌더를 트리거하지 않는 이유는 무엇입니까?
특정 상황에서 알림이 표시되는 알림 컴포넌트(접속 문제, 성공적인 변경 등)를 설계하려고 합니다.
몇 초 후에 알림을 삭제해야 하기 때문에 상태 변경을 트리거하여 알림을 Redux 상태에서 삭제합니다.setTimeout
통지의 내부componentDidMount
.
상태는 변화하지만 React-Redux는 부모 컴포넌트를 재렌더하지 않기 때문에 알림이 DOM에 계속 표시됩니다.
다음은 Redux 리덕터입니다.
const initialState = {
notifications: []
}
export default function (state = initialState, action) {
switch(action.type) {
case CLEAR_SINGLE_NOTIFICATION:
return Object.assign ({}, state, {
notifications: deleteSingleNotification(state.notifications, action.payload)
})
case CLEAR_ALL_NOTIFICATIONS:
return Object.assign ({}, state, {
notifications: []
})
default:
return state
}
}
function deleteSingleNotification (notifications, notificationId) {
notifications.some (function (notification, index) {
return (notifications [index] ['id'] === notificationId) ?
!!(notifications.splice(index, 1)) :
false;
})
return notifications;
}
및 my React 컴포넌트(Main
그리고.Notification
):
/* MAIN.JS */
class Main extends Component {
renderDeletedVideoNotifications() {
console.log('rendering notifications');
const clearNotification = this.props.clearNotification;
return this.props.notifications.map((notification)=> {
return <Notification
key={notification.id}
message={notification.message}
style={notification.style}
clearNotification={clearNotification}
notificationId={notification.id}
/>
});
}
render() {
console.log('rerendering');
return (
<div className="_main">
<Navbar location={this.props.location} logStatus={this.props.logStatus}
logOut={this.logout.bind(this)}/>
<div className="_separator"></div>
{this.props.children}
<BottomStack>
{this.renderDeletedVideoNotifications()}
</BottomStack>
</div>
);
}
}
function mapStateToProps(state) {
return {logStatus: state.logStatus, notifications: state.notifications.notifications};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({checkLogStatus, logOut, clearNotification, clearAllNotifications}, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(Main);
/* NOTIFICATION.JS */
export default class Notification extends Component{
constructor(props){
super(props);
this.state = {show: true}
}
componentWillReceiveProps(nextProps){
if(nextProps.message){
this.setState({show: true});
}
}
clearNotification(notificationId){
this.props.clearNotifications(notificationId);
}
componentDidMount(){
console.log('notification mount');
setTimeout(()=>{
console.log('timed out');
this.props.clearNotification(this.props.notificationId);
}, 1000);
}
closeNotification(){
this.props.clearNotification(this.props.notificationId);
this.setState({show: false});
}
render(){
const notificationStyles = () =>{
if (this.props.style === "error"){
return {backgroundColor: 'rgba(152, 5, 19, 0.8)'}
}
return {backgroundColor: 'rgba(8, 130, 101, 0.8)'}
};
if(!this.state.show){
return null;
}
return (
<div className="notification" style={notificationStyles()}>
<div className="notificationCloseButton" onClick={this.closeNotification.bind(this)}>
<i className="material-icons">close</i>
</div>
{this.props.message}
</div>
)
}
};
모든 것을 올바르게 연결했지만, Redux의 주요 컨셉을 놓치고 있습니다.
Redux를 사용하면 어떤 부분도 변형되지 않습니다.state
.
리듀서 안에서 절대 하지 말아야 할 일:
- 그 주장을 바꾸다.
- API 호출 및 라우팅 전환 등의 부작용을 수행합니다.
- 순수하지 않은 함수(예: Date.now() 또는 Math.random())를 호출합니다.
인deleteSingleNotification
.splice를 사용하여 오래된 알림을 배열에서 잘라냅니다.대신 불필요한 알림이 누락된 새 어레이를 반환해야 합니다.가장 쉬운 방법은 .filter 함수를 사용하는 것입니다.
function deleteSingleNotification(notifications, notificationId){
return notifications.filter (notification => {
return notification.id !== notificationId
}
}
여기 작업 알림 시스템이 있는 JSBin이 있습니다!
이것이 효과가 있는 이유는 다음과 같습니다.React-Redux의 역할은 Redux 스토어의 특정 부분이 변경될 때마다 구성 요소를 업데이트하는 것입니다.를 사용합니다.===
상태 트리의 모든 부분을 테스트하여 변경된 부분이 없는지 확인합니다.
.splice와 같은 것으로 상태를 변경하면 상태를 확인하고 아무것도 다르지 않다고 생각합니다.
다음은 문제를 보여주는 예입니다.
var array = [ 'a', 'b', 'c' ]
var oldArray = array
array.splice (1, 1) // cut out 'b'
oldArray === array // => true! Both arrays were changed by using .splice,
// so React-Redux *doesn't* update anything
대신 React-Redux에서는 다음과 같은 작업을 수행해야 합니다.
var array = [ 'a', 'b', 'c' ]
var oldArray = array
array = array.filter (item, index => index !== 1) // new array without 'b'
oldArray === array // false. That part of your state has changed, so your
// componenet is re-rendered
Redux는 성능상의 이유로 이 방식을 사용합니다.모든 것이 동일한지 확인하기 위해 큰 상태 트리를 루프하는 데 시간이 오래 걸립니다.당신이 나무를 불변하게 유지한다면===
테스트가 필요하며 프로세스가 훨씬 쉬워집니다.
언급URL : https://stackoverflow.com/questions/39513753/my-redux-state-has-changed-why-doesnt-react-trigger-a-re-render
'source' 카테고리의 다른 글
TypeScript 컴파일러가 tsconfig.json을 무시하는 이유는 무엇입니까? (0) | 2023.03.16 |
---|---|
Qt5에서 JSON 파일을 작성/읽기/기입하는 방법 (0) | 2023.03.16 |
수집되지 않은 DOMException:'set'을 실행하지 못했습니다.'스토리지'의 항목:'도메인' 값 설정이 할당량을 초과했습니다. (0) | 2023.03.16 |
AngularJS의 디렉티브에 서비스를 삽입할 수 있습니까? (0) | 2023.03.16 |
구글 프로토콜 버퍼 vs json vs XML (0) | 2023.03.16 |