2016-05-03 2 views
15

Я пытаюсь отделить презентационный компонент от компонента контейнера. У меня есть SitesTable и SitesTableContainer. Контейнер отвечает за запуск действий сокращения, чтобы получить соответствующие сайты на основе текущего пользователя. Проблема заключается в том, что текущий пользователь выбирается асинхронно, после того как компонент контейнера получает рендеринг изначально. Это означает, что компонент контейнера не знает, что ему нужно повторно выполнить код в своей функции componentDidMount, которая будет обновлять данные для отправки в . Думаю, мне нужно перегрузить компонент контейнера, когда один из его реквизита (пользователя) изменится. Как мне это сделать правильно?Компонент реагирования reerender при изменении prop

class SitesTableContainer extends React.Component { 
    static get propTypes() { 
     return { 
     sites: React.PropTypes.object, 
     user: React.PropTypes.object, 
     isManager: React.PropTypes.boolean 
     } 
    } 

    componentDidMount() { 
     if (this.props.isManager) { 
     this.props.dispatch(actions.fetchAllSites()) 
     } else { 
     const currentUserId = this.props.user.get('id') 
     this.props.dispatch(actions.fetchUsersSites(currentUserId)) 
     } 
    } 

    render() { 
     return <SitesTable sites={this.props.sites}/> 
    } 
} 

function mapStateToProps(state) { 
    const user = userUtils.getCurrentUser(state) 

    return { 
    sites: state.get('sites'), 
    user, 
    isManager: userUtils.isManager(user) 
    } 
} 

export default connect(mapStateToProps)(SitesTableContainer); 
+0

у вас есть какие-то другие функции, доступные, как componentDidUpdate, или, возможно, одним вашим ищем, componentWillReceiveProps (nextProps), если вы хотите что-то срабатывает, когда реквизит изменения – thsorens

+0

Зачем вам нужно повторно отображать SiteTable, если он не меняет свои реквизиты? – QoP

+0

@QoP действия, отправленные в 'componentDidMount', изменят узел' sites' в состоянии приложения, который передается в 'SitesTable'. Узлы узлов сайта SitesStable будут меняться. – David

ответ

25

Вы должны добавить условие в свой метод componentWillReceiveProps.

Это как ваш компонент должен выглядеть

constructor(){ 
    this.updateUser = this.updateUser.bind(this); 
} 


componentDidMount() { 
    this.updateUser(); 

} 

componentWillReceiveProps(nextProps) { 
    if(JSON.stringify(this.props.user) !== JSON.stringify(nextProps.user)) // Check if it's a new user, you can also use some unique, like the ID 
    { 
      this.updateUser(); 
    } 
} 

updateUser() { 
    if (this.props.isManager) { 
    this.props.dispatch(actions.fetchAllSites()) 
    } else { 
    const currentUserId = this.props.user.get('id') 
    this.props.dispatch(actions.fetchUsersSites(currentUserId)) 
    } 
} 
+0

Обратите внимание, что JSON.stringify может использоваться только для такого сравнения, если он стабилен (по спецификации это не так), поэтому он производит одинаковый вывод для тех же самых входов. Я рекомендую сравнивать свойства идентификатора объектов пользователя или передавать идентификаторы пользователя в реквизитах и ​​сравнивать их, чтобы избежать ненужных перезагрузок. –

5
componentWillReceiveProps(nextProps) { // your code here} 

Я думаю, что это событие вам нужно. componentWillReceiveProps запускает каждый раз, когда ваш компонент получает что-то через реквизит. Оттуда вы можете проверить, выполняете ли вы все, что хотите.

2

Я бы порекомендовал взглянуть на это answer, и посмотреть, соответствует ли оно тому, что вы делаете. Если я понимаю вашу реальную проблему, просто не используйте свое асинхронное действие правильно и обновляете «store» redux, который автоматически обновит ваш компонент с помощью новых реквизитов.

Этот раздел кода:

componentDidMount() { 
     if (this.props.isManager) { 
     this.props.dispatch(actions.fetchAllSites()) 
     } else { 
     const currentUserId = this.props.user.get('id') 
     this.props.dispatch(actions.fetchUsersSites(currentUserId)) 
     } 
    } 

Не следует запуск в качестве компонента, он должен быть обработан после выполнения вашего первого запроса.

Посмотрите на этот пример из redux-thunk:

function makeASandwichWithSecretSauce(forPerson) { 

    // Invert control! 
    // Return a function that accepts `dispatch` so we can dispatch later. 
    // Thunk middleware knows how to turn thunk async actions into actions. 

    return function (dispatch) { 
    return fetchSecretSauce().then(
     sauce => dispatch(makeASandwich(forPerson, sauce)), 
     error => dispatch(apologize('The Sandwich Shop', forPerson, error)) 
    ); 
    }; 
} 

Вы не обязательно должны использовать Redux-преобразователь,, но это поможет вам причину о сценариях, как это и писать код, чтобы соответствовать.

+0

прав, я понимаю. Но где именно вы отправляете 'makeASandwichWithSecretSauce' в свой компонент? – David

+0

Я свяжу вас с репо с соответствующим примером, используете ли вы взаимодействие с вашим приложением? – TameBadger

+0

Да, я использую реактивный маршрутизатор – David

Смежные вопросы