laravel5.5 + react完成簡單的CRUD

laravel5.5 + react完成簡單的CRUD

在這篇文章中雪猪,我想和大家分享如何在PHP Laravel框架中使用js來創(chuàng)建crud(Create Read Update Delete)應(yīng)用程序栏尚。在這個例子中,您可以學(xué)習(xí)如何為laravel reactjs應(yīng)用程序構(gòu)建設(shè)置只恨,我還使用axios post請求官觅,獲取請求休涤,放入請求和刪除請求來插入更新刪除應(yīng)用程序功氨。

教程大概分為如下9步

  • 1.1) 第1步:安裝Laravel 5.5
  • 1.2) 第2步:數(shù)據(jù)庫配置
  • 1.3) 第3步:創(chuàng)建產(chǎn)品表格和模型
  • 1.4) 第4步:創(chuàng)建Web路由和API路由
  • 1.5) 第5步:創(chuàng)建ProductController
  • 2.0) 第6步:安裝ReactJS的配置
  • 3.0) 第7步:創(chuàng)建React組件文件
  • 4.0) 第8步:創(chuàng)建視圖文件
  • 5.0) 第9步:運行項目

1. 安裝laravel5.5

1.1 創(chuàng)建項目

composer create-project laravel/laravel laravel-react --prefer-dist

1.2 修改數(shù)據(jù)庫配置

創(chuàng)建數(shù)據(jù)庫并修改配置文件

cd laravel-react

vim .env

1.3 創(chuàng)建文章遷移表及模型

php artisan make:model Post -m
1

這樣就創(chuàng)建好了Post模型以及posts

當(dāng)然你也可以分兩步執(zhí)行

// 創(chuàng)建Post 模型
php artisan make:model Post
// 創(chuàng)建posts表
php artisan make:migration create_posts_table

修改遷移文件的up方法
database/migrations/2018_01_23_021301_create_posts_table.php

    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title');
            $table->text('content');
            $table->timestamps();
        });
    }

執(zhí)行遷移

php artisan migrate
2

修改app/Post.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    protected $fillable = [
        'title', 'body'
    ];
}

1.4 創(chuàng)建web路由和api路由

routes/web.php

Route::get('/', function () {
    return view('welcome');
});

routes/api.php

Route::resource('posts', 'PostController');

1.5 創(chuàng)建PostController

php artisan make:controller PostController --resource

--resource 會默認(rèn)創(chuàng)建以下方法

  1. index()
  2. store()
  3. edit()
  4. update()
  5. destory()
    6) show() 這里暫時我們不需要這個方法

修改 app/Http/PostController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Post;

class PostController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $data = Post::all();
        return response()->json($data);
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create(Request $request)
    {
        $data = new Post([
          'title' => $request->get('title'),
          'content' => $request->get('content')
        ]);
        $data->save();

        return response()->json('添加成功 :)');
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $data = new Post([
          'title' => $request->get('title'),
          'content' => $request->get('content')
        ]);
        $data->save();

        return response()->json('保存成功 :)');
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        $data = Post::find($id);
        return response()->json($data);
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        $data = Post::find($id);
        $data->title = $request->get('title');
        $data->content = $request->get('content');
        $data->save();

        return response()->json('修改成功 :)');
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        $data = Post::find($id);
        $data->delete();

        return response()->json('刪除成功 :)');
    }
}

2. 安裝ReactJS

修改前端預(yù)置

php artisan preset react

npm 安裝

npm install

運行

npm run dev

安裝react router

npm install react-router@2.8.1

3. 創(chuàng)建React組件文件

我們需要創(chuàng)建的文件列表如下:

  • 1)app.js
  • 2)bootstrap.js
  • 3)組件/ CreatePost.js
  • 4)組件/ DisplayPost.js
  • 5)組件/ MasterPost.js
  • 6)組件/ MyGlobleSetting.js
  • 7)組件/ TableRow.js
  • 8)組件/ UpdatePost.js

resources/assets/js/app.js

require('./bootstrap');
import React from 'react';
import { render } from 'react-dom';
import { Router, Route, browserHistory } from 'react-router';


import Master from './components/Master';
import CreatePost from './components/CreatePost';
import DisplayPost from './components/DisplayPost';
import UpdatePost from './components/UpdatePost';


render(
  <Router history={browserHistory}>
      <Route path="/" component={Master} >
        <Route path="/add-item" component={CreatePost} />
        <Route path="/display-item" component={DisplayPost} />
        <Route path="/edit/:id" component={UpdatePost} />
      </Route>
    </Router>,
        document.getElementById('crud-app'));

resources/assets/js/bootstrap.js

window._ = require('lodash');


try {
    window.$ = window.jQuery = require('jquery');


    require('bootstrap-sass');
} catch (e) {}


window.axios = require('axios');


window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

let token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}

resources/assets/js/components/CreatePost.js

import React, {Component} from 'react';
import {browserHistory} from 'react-router';
import MyGlobleSetting from './MyGlobleSetting';


class CreatePost extends Component {
  constructor(props){
    super(props);
    this.state = {postTitle: '', postContent: ''};


    this.handleChange1 = this.handleChange1.bind(this);
    this.handleChange2 = this.handleChange2.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);


  }
  handleChange1(e){
    this.setState({
      postTitle: e.target.value
    })
  }
  handleChange2(e){
    this.setState({
      postContent: e.target.value
    })
  }
  handleSubmit(e){
    e.preventDefault();
    const posts = {
      title: this.state.postTitle,
      content: this.state.postContent
    }
    let uri = MyGlobleSetting.url + '/api/posts';
    axios.post(uri, posts).then((response) => {
      browserHistory.push('/display-item');
    });
  }


    render() {
      return (
      <div>
        <h1>Create Post</h1>
        <form onSubmit={this.handleSubmit}>
          <div className="row">
            <div className="col-md-6">
              <div className="form-group">
                <label>Post Title:</label>
                <input type="text" className="form-control" onChange={this.handleChange1} />
              </div>
            </div>
            </div>
            <div className="row">
              <div className="col-md-6">
                <div className="form-group">
                  <label>Post Content:</label>
                  <textarea className="form-control col-md-6" onChange={this.handleChange2}></textarea>
                </div>
              </div>
            </div><br />
            <div className="form-group">
              <button className="btn btn-primary">Add Post</button>
            </div>
        </form>
  </div>
      )
    }
}
export default CreatePost;

resources/assets/js/components/DisplayPost.js

import React, {Component} from 'react';
import axios from 'axios';
import { Link } from 'react-router';
import TableRow from './TableRow';
import MyGlobleSetting from './MyGlobleSetting';
class DisplayPost extends Component {
  constructor(props) {
    super(props);
    this.state = {value: '', posts: ''};
  }
  componentDidMount(){
   axios.get(MyGlobleSetting.url + '/api/posts')
   .then(response => {
     this.setState({ posts: response.data });
   })
   .catch(function (error) {
     console.log(error);
   })
  }
  tabRow(){
   if(this.state.posts instanceof Array){
     return this.state.posts.map(function(object, i){
        return <TableRow obj={object} key={i} />;
     })
   }
  }


  render(){
    return (
      <div>
        <h1>Post</h1>


        <div className="row">
          <div className="col-md-10"></div>
          <div className="col-md-2">
            <Link to="/add-item">Create Post</Link>
          </div>
        </div><br />


        <table className="table table-hover">
            <thead>
            <tr>
                <td>ID</td>
                <td>Post Title</td>
                <td>Post Content</td>
                <td width="200px">Actions</td>
            </tr>
            </thead>
            <tbody>
              {this.tabRow()}
            </tbody>
        </table>
    </div>
    )
  }
}
export default DisplayPost;

resources/assets/js/components/Master.js

import React, {Component} from 'react';
import { Router, Route, Link } from 'react-router';


class Master extends Component {
  render(){
    return (
      <div className="container">
        <nav className="navbar navbar-default">
          <div className="container-fluid">
            <div className="navbar-header">
              <a className="navbar-brand" >bear777.com</a>
            </div>
            <ul className="nav navbar-nav">
              <li><Link to="/">Home</Link></li>
              <li><Link to="add-item">Create Post</Link></li>
              <li><Link to="display-item">Post List</Link></li>
            </ul>
          </div>
      </nav>
          <div>
              {this.props.children}
          </div>
      </div>
    )
  }
}
export default Master;

resources/assets/js/components/MyGlobleSetting.js

class MyGlobleSetting {
  constructor() {
    this.url = 'http://localhost:8000';
  }
}
export default (new MyGlobleSetting);

resources/assets/js/components/TableRow.js

import React, { Component } from 'react';
import { Link, browserHistory } from 'react-router';
import MyGlobleSetting from './MyGlobleSetting';


class TableRow extends Component {
  constructor(props) {
      super(props);
      this.handleSubmit = this.handleSubmit.bind(this);
  }
  handleSubmit(event) {
    event.preventDefault();
    let uri = MyGlobleSetting.url + `/api/posts/${this.props.obj.id}`;
    axios.delete(uri);
      browserHistory.push('/display-item');
  }
  render() {
    return (
        <tr>
          <td>
            {this.props.obj.id}
          </td>
          <td>
            {this.props.obj.title}
          </td>
          <td>
            {this.props.obj.content}
          </td>
          <td>
          <form onSubmit={this.handleSubmit}>
            <Link to={"edit/"+this.props.obj.id} className="btn btn-primary">Edit</Link>
           <input type="submit" value="Delete" className="btn btn-danger"/>        
         </form>
          </td>
        </tr>
    );
  }
}


export default TableRow;

resources/assets/js/components/UpdatePost.js

import React, {Component} from 'react';
import axios from 'axios';
import { Link } from 'react-router';
import MyGlobleSetting from './MyGlobleSetting';


class UpdatePost extends Component {
  constructor(props) {
      super(props);
      this.state = {title: '', content: ''};
      this.handleChange1 = this.handleChange1.bind(this);
      this.handleChange2 = this.handleChange2.bind(this);
      this.handleSubmit = this.handleSubmit.bind(this);
  }


  componentDidMount(){
    axios.get(MyGlobleSetting.url + `/api/posts/${this.props.params.id}/edit`)
    .then(response => {
      this.setState({ title: response.data.title, content: response.data.content });
    })
    .catch(function (error) {
      console.log(error);
    })
  }
  handleChange1(e){
    this.setState({
      title: e.target.value
    })
  }
  handleChange2(e){
    this.setState({
      content: e.target.value
    })
  }


  handleSubmit(event) {
    event.preventDefault();
    const posts = {
      title: this.state.title,
      content: this.state.content
    }
    let uri = MyGlobleSetting.url + '/api/posts/'+this.props.params.id;
    axios.patch(uri, posts).then((response) => {
          this.props.history.push('/display-item');
    });
  }
  render(){
    return (
      <div>
        <h1>Update Post</h1>
        <div className="row">
          <div className="col-md-10"></div>
          <div className="col-md-2">
            <Link to="/display-item" className="btn btn-success">Return to Post</Link>
          </div>
        </div>
        <form onSubmit={this.handleSubmit}>
            <div className="form-group">
                <label>Post Title</label>
                <input type="text"
                  className="form-control"
                  value={this.state.title}
                  onChange={this.handleChange1} />
            </div>


            <div className="form-group">
                <label name="post_content">Post Content</label>
                <textarea className="form-control"
                  onChange={this.handleChange2} value={this.state.content}></textarea>  
            </div>


            <div className="form-group">
                <button className="btn btn-primary">Update</button>
            </div>
        </form>
    </div>
    )
  }
}
export default UpdatePost;

4. 創(chuàng)建主視圖文件

resources/views/welcome.blade.php

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Laravel 5.5 ReactJS CRUD Example</title>
        <link href="{{asset('css/app.css')}}" rel="stylesheet" type="text/css">
    </head>
    <body>
        <div id="crud-app"></div>
        <script src="{{asset('js/app.js')}}" ></script>
    </body>
</html>

為了避免Laravel CSRF報錯
我們在視圖文件head加入

<meta name="csrf-token" content="{{ csrf_token() }}">

<script>
window.Laravel = <?php echo json_encode([
    'csrfToken' => csrf_token(),
]); ?>
</script>

完整視圖
resources/views/welcome.blade.php

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="csrf-token" content="{{ csrf_token() }}">
        <title>Laravel 5.5 ReactJS CRUD Example</title>
        <link href="{{asset('css/app.css')}}" rel="stylesheet" type="text/css">
        <script>
        window.Laravel = <?php echo json_encode([
            'csrfToken' => csrf_token(),
        ]); ?>
        </script>
    </head>
    <body>
        <div id="crud-app"></div>
        <script src="{{asset('js/app.js')}}" ></script>
    </body>
</html>

5. 編譯&運行

編譯

npm run dev

artisan運行項目

php artisan serve

訪問 http://localhost:8000 即可

效果圖

圖1
圖2

主要參考資料 Laravel 5.5 ReactJS Tutorial

本教程翻譯于 Laravel 5 - Simple CRUD Application Using ReactJS

github地址 https://github.com/pandoraxm/laravel-react-curd

原文鏈接 https://www.bear777.com/blog/laravel5-5-react-crud

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市演闭,隨后出現(xiàn)的幾起案子米碰,更是在濱河造成了極大的恐慌购城,老刑警劉巖瘪板,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侮攀,死亡現(xiàn)場離奇詭異,居然都是意外死亡撇叁,警方通過查閱死者的電腦和手機(jī)税朴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門正林,熙熙樓的掌柜王于貴愁眉苦臉地迎上來觅廓,“玉大人涵但,你說我怎么就攤上這事⊥В” “怎么了劫侧?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵烧栋,是天一觀的道長。 經(jīng)常有香客問我珍特,道長扎筒,這世上最難降的妖魔是什么画畅? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮症脂,結(jié)果婚禮上淫僻,老公的妹妹穿的比我還像新娘雳灵。我一直安慰自己,他們只是感情好琳省,可當(dāng)我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布针贬。 她就那樣靜靜地躺著桦他,像睡著了一般谆棱。 火紅的嫁衣襯著肌膚如雪垃瞧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天拦宣,我揣著相機(jī)與錄音鸵隧,去河邊找鬼豆瘫。 笑死菊值,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的昵宇。 我是一名探鬼主播瓦哎,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼蒋譬,長吁一口氣:“原來是場噩夢啊……” “哼愉适!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起剂买,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤瞬哼,失蹤者是張志新(化名)和其女友劉穎倒槐,沒想到半個月后附井,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體永毅,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡沼死,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了健芭。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片秀姐。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡省有,死狀恐怖蠢沿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情恤磷,我是刑警寧澤雪侥,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布速缨,位于F島的核電站,受9級特大地震影響仿粹,放射性物質(zhì)發(fā)生泄漏原茅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一晌区、第九天 我趴在偏房一處隱蔽的房頂上張望朗若。 院中可真熱鬧昌罩,春花似錦、人聲如沸茎用。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽琉预。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間啄栓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工近速, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留削葱,地道東北人淳梦。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓爆袍,卻偏偏與公主長得像,于是被迫代替她去往敵國和親弦疮。 傳聞我的和親對象是個殘疾皇子胁塞,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容