質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.05%

[React.js]stateが正常にsetされない。

解決済

回答 2

投稿

  • 評価
  • クリップ 1
  • VIEW 321

wisheebell

score 7

前提・実現したいこと

現在React.jsでテキストのCRUDを実装しています。
投稿したデータはaxiosを使ってrailsサーバーのデータベースに保存されます。

投稿されたテキストを後から編集する機能を実装する際に、stateがうまく反映されず困っています。。。
handleSubmit内でsetStateをしているのですが、stateの内容が変更されていません。

該当のソースコード

import React, { Component } from 'react';
import update from 'react-addons-update';
import axios from 'axios';
import TextField from '@material-ui/core/TextField';
import Button from '@material-ui/core/Button';

class Form extends Component {
  constructor(props) {
    super(props);
    this.state = {
      post: {},
      title: '',
      content: ''
    };
    this.handleChange = this.handleChange.bind(this);
    this.handleContentChange = this.handleContentChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  componentDidMount() {
    axios
      .get(`http://192.168.99.100:3001/api/v1/posts/${this.props.match.params.id}`)
      .then((results) => {
        console.log(results);
        this.setState({ post: results.data, title: results.data.title, content: results.data.content});
      })
      .catch((data) =>{
        console.log(data);
        return(<h1>not found(404)</h1>);
      });
  }

  handleChange = title => event => {
    this.setState({title: event.target.value});
  };

  handleContentChange = content => event => {
    this.setState({content: event.target.value});
  };

  handleSubmit = () => {
    const titleUpdate = update(this.state.post, {title: {$set: this.state.title}})
    console.log('title update')
    console.log(titleUpdate)

    const contentUpdate = update(titleUpdate, {content: {$set: this.state.content}})
    console.log('content update')
    console.log(contentUpdate)

    this.setState({post: contentUpdate})
    console.log('state set')
    console.log(this.state.post)

    console.log('this post id')
    console.log(this.props.match.params.id)

    this.props.updatePost(this.props.match.params.id, this.state.post)
  }

  render(){
    return (
      <div>
        <form noValidate autoComplete="off">
          <TextField
            id="standard-full-width"
            label="Title"
            onChange={this.handleChange('title')}
            fullWidth
            margin="normal"
            variant="outlined"
            value={this.state.title}
          />
          <hr />
          <br />
          <TextField
            id="outlined-multiline-static"
            label="Content"
            multiline
            rows="30"
            fullWidth
            onChange={this.handleContentChange('content')}
            margin="normal"
            variant="outlined"
            value={this.state.content}
          />
        </form>
        <Button variant="contained" onClick={this.handleSubmit}>
          submit
        </Button>
      </div>
    );
  }
}

export default Form;


"this.props.updatePost"は投稿したデータを更新するメソッドです

試したこと

コンソールに逐一出力して値を確認してみたところ、"titleUpdate",#contentUpdate"は正常に定義されているようなのですが、setStateしてもPostが変更されていないようです。

補足情報(FW/ツールのバージョンなど)

react: 16.9.0
react-addons-update: 15.6.2
material-ui: 4.4.0

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

0

this.setState非同期で実行されますので、直後の行ではまだstateは変更されません。

stateを参照せずに、変更に使った値をそのまま使うようにしましょう。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/09/09 11:07

    ありがとうございます
    解決しました

    キャンセル

0

こんにちは

ご質問に挙げられているソースコードの以下の部分(※console.logは省略しました。)

修正前:

this.setState({post: contentUpdate})

this.props.updatePost(this.props.match.params.id, this.state.post)


で、 updatePost は this.setState によって this.state の内容が変更された後に呼ばれることを意図しているものと思われますが、この前後関係を担保するには、setState の第2引数にコールバックを与えて、そこで(変更後想定の) this.stateを使うコードを書けばよいかと思います。

したがって、以下のように修正してみると、いかがでしょうか?

修正後:

this.setState(
  { post: contentUpdate },
  () => {  
    this.props.updatePost(this.props.match.params.id, this.state.post)
  }
)

以下もご参考まで

  • react公式ドキュメントの setState の説明からの引用:

setState(object nextState[, function callback])
  ・・・ In addition, you can supply an optional callback function that is executed once setState is completed and the component is re-rendered.

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/09/09 11:06

    なるほど。
    そのような書き方もできるんですね
    参考になります

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.05%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る