Emacs for React

  • 使用 rjsx-mode:是 js2-mode 衍伸出來的主模式,因此也繼承了 js2-mode 的功能
  • 語法檢查:使用本地 eslint + react-app
  • 使用 emmet 加上 className
  • 排版美化:使用 prettier-js

Youtube 影片

安裝 rjsx-mode

(use-package rjsx-mode
:ensure t
:mode (“\\.js\\'”)
:config
(setq js2-basic-offset 2)
(add-hook ‘rjsx-mode-hook (lambda()
(flycheck-add-mode ‘javascript-eslint ‘rjsx-mode)
(my/use-eslint-from-node-modules)
(flycheck-select-checker ‘javascript-eslint)
))
)

其他安裝

  • 將 rjsx-mode 加入 emmet-mode

    :hook (web-mode css-mode scss-mode sgml-mode rjsx-mode)

  • emmet 在 web-mode 要用 class 而 rjsx-mode 用 className

    (use-package mode-local
    :ensure t
    :config
    (setq-mode-local rjsx-mode emmet-expand-jsx-className? t)
    (setq-mode-local web-mode emmet-expand-jsx-className? nil)
    )

  • 使用 react-snippets 套件

    (use-package react-snippets
    :ensure t)

使用 tide

(add-hook ‘rjsx-mode-hook #’setup-tide-mode)

開始一個專案

$create-react-app hello
  • 加入 bootstrap CDN 到 public/index.html
  • 清掉 index.css

在 vagrant client 中,需加入 .env

CHOKIDAR_USEPOLLING=true

建立一個 Components

  • 建立 Components 目錄
  • 建立 Posts.js
    import React from "react";
    
    class Posts extends React.Component {
    render() {
      return (
        <div className="Posts">
          <h3>List of Posts</h3>
          </div>
          );
        }
      }
    
    export default Posts;
    

使用 mock-posts 從 App.js 傳到 Posts.js

import React, { Component } from "react";
import Posts from "./Components/Posts";
import "./App.css";

class App extends Component {
  constructor() {
    super();
    this.state = {
      posts: [
        { id: 1, title: "first post", body: "this is first post content" },
        { id: 2, title: "second post", body: "this is second post content" },
        { id: 1, title: "third post", body: "this is third post content" },
        { id: 1, title: "forth post", body: "this is forth post content" },
      ],
    };
  }
  render() {
    return (
      <div className="App">
        <Posts posts={this.state.posts} />
      </div>
    );
  }
}

export default App;

Posts Component 應該會收到這個 props

import React from "react";

class Posts extends React.Component {
  render() {
    console.log(this.props);
    return (
      <div className="Posts">
        <h3>List of Posts</h3>
        </div>
      );
    }
  }

  export default Posts;

建立 Post Component

import React from "react";

class Post extends React.Component {
  render() {
    return (
      <div className="col-md-6">
        <div className="card mb-4 shadow-sm">
          <div className="card-body">
            <div className="card-title">{this.props.post.title}</div>
            <div className="card-text mb-3">{this.props.post.body}</div>
            <a href="#" className="btn btn-outline-primary">
              More...
            </a>
          </div>
        </div>
      </div>
    );
  }
}

export default Post;

App.js 將 posts 移到 componentWillMount

import React, { Component } from "react";
import Posts from "./Components/Posts";
import "./App.css";

class App extends Component {
  constructor() {
    super();
    this.state = {
      posts: [],
    };
  }

  componentWillMount() {
    this.setState({
      posts: [
        { id: 1, title: "first post", body: "this is first post content" },
        { id: 2, title: "second post", body: "this is second post content" },
        { id: 1, title: "third post", body: "this is third post content" },
        { id: 1, title: "forth post", body: "this is forth post content" },
      ],
    });
  }
  render() {
    return (
      <div className="App">
        <Posts posts={this.state.posts} />
      </div>
    );
  }
}

export default App;

使用 fetch 來 get API

import React, { Component } from "react";
import Posts from "./Components/Posts";

import "./App.css";

class App extends Component {
  constructor() {
    super();
    this.state = {
      posts: [],
    };
  }

  componentDidMount() {
  // this.setState({
  //   posts: [
  //     { id: 1, title: "first post", body: "this is first post content" },
  //     { id: 2, title: "second post", body: "this is second post content" },
  //     { id: 1, title: "third post", body: "this is third post content" },
  //     { id: 1, title: "forth post", body: "this is forth post content" },
  //   ],
  // });

  fetch("https://jsonplaceholder.typicode.com/posts?userId=1")
    .then(res => res.json())
    //.then(data => console.log(data));
    .then(data => this.setState({ posts: data }));
  }
  render() {
    return (
      <div className="App">
        <Posts posts={this.state.posts} />
      </div>
    );
  }
}

export default App;

修改 Post.js

import React from "react";

class Post extends React.Component {
  render() {
    return (
      <div className="Post col-md-6">
        <div className="card mb-4 shadow-sm">
          <div className="card-body">
            <div className="card-title">{this.props.post.title}</div>
            <div className="card-text mb-3">
              {this.props.post.body.substring(0, 50)}
              ...
            </div>
            <a href="#" className="btn btn-outline-primary">
              More...
            </a>
          </div>
        </div>
      </div>
    );
  }
}

export default Post;

最後 Posts.js

import React from "react";

import Post from "./Post";

class Posts extends React.Component {
  render() {
    let posts;
    if (this.props.posts) {
      posts = this.props.posts.map(post => {
        //console.log(post);
        return <Post key={post.title} post={post} />;
      });
    }

    return (
      <div className="Posts">
        <div className="container">
          <h3 className="my-4 text-center">List of Posts</h3>
          <div className="row">{posts}</div>
        </div>
      </div>
    );
  }
}

export default Posts;

2 則迴響

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *