Обновление базы данных из переменной состояния при изменении состояния - PullRequest
0 голосов
/ 21 марта 2019

Я пытаюсь обновить базу данных, используя переменную состояния, когда нажата кнопка сохранения. В обработчике сохранения новое значение добавляется в список this.state.saved и вызывается функция updataDatabase. Проблема заключается в том, что при нажатии кнопки setState не обновляет переменную состояния, поэтому в базе данных ничего не обновляется. Мой вопрос: как я могу заставить setState обновить компонент, чтобы база данных была обновлена? Это мой код

class Articles extends Component{
    constructor(props){
        super(props);
        this.state = {
            check:false,
            saved:[]
        }

        this.handleSave = this.handleSave.bind(this)
    }

    async componentDidMount(){
        savedArticles = this.props.article.saved

        this.setState({
            check:this.props.article.check,
            saved:this.props.article.saved
    })
}

async updateDataBase(){
    let updates = {
        body:{
            userName:this.props.article.user,
            userEmail:this.props.article.email,
            userPhone:this.props.article.phone,
            savedArticles:this.state.saved,
            userInterests:this.props.article.interestList,

        }


    }
    console.log(updates)

    return await API.put(apiName,path,updates);
}

handleSave () {
    const urlList = [];
    let article = {};

    for(let i=0; i<this.state.saved.length; i++){
        urlList.push(this.state.saved[i].url)
    }
    if(!urlList.includes(this.props.article.url)){

        article =  {
            url:this.props.article.url,
            title:this.props.article.title,
            image:this.props.article.urlToImage,
            author:this.props.article.author,
            check:true,

        }
        savedArticles.push(article)
            this.setState({
                check: true,
                saved:[...this.state.saved,article]

            })


        this.updateDataBase();

    }
}

render()
{
    console.log(this.state.check)

    return (
        <div className="item">
            <div className="card">
                <img src={this.props.article.urlToImage} alt="No available image" width="100%" height="200px"></img>
                <div>

                    <h5 className="card-title">{this.props.article.title}</h5>
                    <p className="card-text">{this.props.article.author}</p>
                    <a href={this.props.article.url} target="_blank" id="articleLink" className="btn btn-primary"><FontAwesomeIcon icon="external-link-alt" /> See full article</a>

                    {this.state.check?(
                        <button disabled={true}  id="buttonsArticle" className="btn btn-primary"><FontAwesomeIcon icon="check" /> Saved</button>
                    ):(
                        <button onClick={this.handleSave.bind(this)} id="buttonsArticle" className="btn btn-primary"><FontAwesomeIcon icon="save" /> Save Article</button>
                    )}

                </div>
            </div>
            <div className="divider"></div>
        </div>

    )
}}

1 Ответ

0 голосов
/ 21 марта 2019

Проблема в том, что ваш код работает синхронно. Вы устанавливаете состояние и затем вызываете this.updateDataBase();, но состояние не будет обновлено в этом контексте. Состояние фактически обновляется, и последующий рендеринг происходит после этого. Вы можете представить, что он работает как очередь, в которой вы вызываете setState, он принимает к сведению, что необходимо обновить состояние, но все остальное, что находится в очереди, должно выполняться в первую очередь.

Взгляните на это: https://codesandbox.io/s/32n06zlqop?fontsize=14 Если вы нажмете кнопку, она сразу выйдет из состояния, в котором она ложна, а затем снова выйдет из нее в componentDidUpdate, и вы увидите, что состояние установлено то.

Таким образом, у вас есть два варианта, вы можете вызывать функцию обновления базы данных внутри метода componentDidUpdate жизненного цикла. Эта функция вызывается после каждого рендера, который может быть вызван изменением состояния.

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

this.setState({
      check: true,
      saved:[...this.state.saved, article]
    }, this.updateDataBase)
...