2016-02-14 3 views
1

У меня есть канал, где вы можете отправлять записи. Эти записи могут понравиться любому пользователю. Проблема в том, что после того, как вам понравится запись и продолжайте писать свою запись сразу после (таким образом, нажав новую запись в начало фида), состояние всех подобных кнопок, которые вы нажали, будет отменено визуально и для того, чтобы см. правильные данные, отображаемые вручную.React Rails - Как состояние кнопки, не обновляющееся должным образом

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

Вот мой код Как компонент (like.es6.jsx):

class Like extends React.Component { 
    constructor(props){ 
     super(props); 
     this.state={ 
      like: this.props.entry.liked, 
      likes: this.props.entry.likes_count 
     } 
     this.post = this.post.bind(this); 
     this.delete = this.delete.bind(this); 
    } 

    post() { 
     if(!(this.state.like)){ 
      $.ajax({ 
        method: "POST", 
        url: "/api/v1/likes", 
        data: { 
         log_entry_id: this.props.entry.id 
        }, 
       }) 
       .then((response) => { 
        this.setState({like: true}) 
        let likes = this.state.likes; 
        likes++; 
        this.setState({likes: likes}) 
       }); 
     } 
    } 

    delete(){ 
     if(this.state.like){ 
      $.ajax({ 
        method: "DELETE", 
        url: "/api/v1/likes/" + this.props.entry.id 
       }) 
       .then((response) => { 
        this.setState({like: false}) 
        let likes = this.state.likes; 
        likes--; 
        this.setState({likes: likes}) 
       }); 
     } 
    } 

    render() { 
     let show_likes = ""; 
     if(this.state.like) { 
      show_likes = (this.state.likes > 1) ? ("You and " + (this.state.likes - 1) + ((this.state.likes == 2) ? (" other person") : (" others")) + (" like this.")) : ("You like this."); 
     }else if(this.state.likes > 0){ 
      show_likes = (this.state.likes == 1) ? (this.state.likes + " person likes this.") : (this.state.likes + " people like this."); 
     } 
     let like_button = this.state.like ? 
      <a onClick={this.delete} className=" pull-right"><i className="fa fa-thumbs-o-down"></i> Dislike</a> : 
      <a onClick={this.post} className=" pull-right"><i className="fa fa-thumbs-o-up"></i> Like</a> 
     return (
      <div> 
      <span> 
       {show_likes} 
      </span> 
       {like_button} 
      </div> 
     ); 
    } 
} 

В родительском компоненте «log_entry.es6.jsx» Я добавил мой как компонент следующим образом:

<Like entry={entry} key={entry.id} /> 

Если есть дополнительная информация, которую я могу предоставить, я с радостью сделаю это по запросу. Спасибо, что посмотрели мою проблему.

ответ

0

Я попытался переместить функции и обработчики состояния в родительский компонент. Однако это оказалось очень неприятным из-за того, что родительский элемент моей кнопки «Я» также имел родителя (возможно, я мог бы исчерпать этот метод дальше, но я нашел другой способ).

Моего решения закончилось тем, что это:

class Like extends React.Component { 
    constructor(props){ 
     super(props); 
     this.state={ 
      like: this.props.entry.liked, 
      likes: this.props.entry.likes_count 
     } 
     this.post = this.post.bind(this); 
     this.delete = this.delete.bind(this); 
    } 

    post() { 
     if(!(this.state.like)){ 
      $.ajax({ 
        method: "POST", 
        url: "/api/v1/likes", 
        data: { 
         log_entry_id: this.props.entry.id 
        }, 
       }) 
       .then((response) => { 
        this.setState({like: true}) 
        let likes = this.state.likes; 
        likes++; 
        this.setState({likes: likes}); 
        this.props.entry.liked = true; 
        this.props.entry.likes_count = likes; 
       }); 
     } 
    } 

    delete(){ 
     if(this.state.like){ 
      $.ajax({ 
        method: "DELETE", 
        url: "/api/v1/likes/" + this.props.entry.id 
       }) 
       .then((response) => { 
        this.setState({like: false}) 
        let likes = this.state.likes; 
        likes--; 
        this.setState({likes: likes}); 
        this.props.entry.liked = false; 
        this.props.entry.likes_count = likes; 
       }); 
     } 
    } 

    render() { 
     let show_likes = ""; 
     if(this.state.like) { 
      show_likes = (this.state.likes > 1) ? ("You and " + (this.state.likes - 1) + ((this.state.likes == 2) ? (" other person") : (" others")) + (" like this.")) : ("You like this."); 
     }else if(this.state.likes > 0){ 
      show_likes = (this.state.likes == 1) ? (this.state.likes + " person likes this.") : (this.state.likes + " people like this."); 
     } 
     let like_button = this.state.like ? 
      <a onClick={this.delete} className=" pull-right"><i className="fa fa-thumbs-o-down"></i> Dislike</a> : 
      <a onClick={this.post} className=" pull-right"><i className="fa fa-thumbs-o-up"></i> Like</a> 
     return (
      <div> 
      <span> 
       {show_likes} 
      </span> 
       {like_button} 
      </div> 
     ); 
    } 
} 

Что я прибавлял 2 строки по обеим должностям и функции удаления.

this.props.entry.liked = true; 
this.props.entry.likes_count = likes; 

this.props.entry.liked = false; 
this.props.entry.likes_count = likes; 

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

1

Когда вы «продолжаете писать свою собственную запись», обновляет ли это this.state в родительском компоненте? Если да, я уверен, что это вызывает Like для повторной обработки с помощью своих реквизитов, которые стали устаревшими!

Думайте об этом так: entry, переданный в <Like entry={entry} />, включает только данные, которые были истинны при начальной загрузке страницы. Когда пользователь нажимает «нравится», он обновляет this.date компонента Like, но оригиналentry был не обновлен!

Итак, если что-то заставляет Like повторно отобразить с entry, он будет отображаться с простыми данными! Но если вы обновите страницу, она будет извлекать последние данные и отображать их правильно.

Это звучит как вероятная причина?

Лучшее решение, о котором я могу думать, это шаблон container component. В этом шаблоне только один компонент (в верхней части дерева) имеет this.state. Он отправляет данные своим детям в качестве реквизита. Только компонент контейнера отправляет запросы и обновления AJAX this.state.

В вашем случае, это будет означать перемещение post и delete функции родительского компонента, и передавая их в Like как обработчики событий (например, <Like onLike={this.post} onUnlike={this.delete} ...>) Тогда, в Like, вы можете использовать их как на кнопку обработчиков , например, onClick={this.onLike}.

Хотя это требует тщательной организации, это действительно окупается, потому что каждый render очень предсказуем: единственное, что может изменить этот контейнер this.state, все остальное делают только из this.props!

+0

Благодарю вас за ответ. Это похоже на вероятную причину да, и я попытаюсь реализовать это решение в своем коде. Я вернусь к вам с тем, что получаю :) – lax1n