1. 程式人生 > 其它 >【重點突破】—— create-react-app&React元件化思想

【重點突破】—— create-react-app&React元件化思想

技術標籤:javavuereact分散式python

前言:正在學習react大眾點評專案課程的todoList應用階段,學習react、redux、react-router基礎知識。


一、 React專案腳手架:create-react-app

  • 新建專案:
    npx create-react-app 專案名
    
    

    注:(npm >= 5.2 )  

  • 三個依賴:react、react-dom、react-scripts
  • 四個命令:start、build、test、eject(將webpack的封裝彈射出來)
    cd 專案名
    
    npm start (npm run start中run可省略)

二、使用Mock資料 —— 前後端分離模擬通過http獲取mock資料的過程

方式一: 代理到mock伺服器

需要開啟一臺mock伺服器,將前端請求轉發到這臺mock伺服器上

安裝:

npm install -g serve 

啟動:

serve

伺服器地址:http://localhost:5000  

新建api目錄,建立data.json檔案

腳手架集成了請求轉發的功能:package.json檔案中

1.create-react-app腳手架低於2.0版本時候,可以使用物件型別

"proxy": {
     "/api": {
          "target": "http://localhost:5000",
          "changeOrigin": true
     }
}  

2.最新的create-react-app腳手架2.0版本以上只能配置string型別

"proxy": "http://localhost:5000" 

3.最好的方式可以通過middleware中介軟體進行配置(可以配置多個代理)

npm install http-proxy-middleware --save

const proxy = require("http-proxy-middleware");

module.exports = function(app) {
      app.use(
          proxy("/api/", {
                target: "http://localhost:5000",//跨域地址
                changeOrigin: true
          })
      );
};

請求地址:localhost:3000/api/data.json

注意:package.json內容發生了修改,必須重啟應用,才能生效。

方式二: 直接將mock資料放到專案public/mock資料夾下(採用)

原因:public資料夾下的內容不會被構建,是靜態資源,可直接使用,這樣在伺服器上,就可以用http方式請求到mock資料了。

三、React思維方式:元件化思想

1.元件劃分原則

解耦:降低單一模組/元件的複雜度

複用:保證元件一致性,提升開發效率

元件顆粒度需要避免過大或過小!

2.編寫靜態元件

開發過程解耦:靜態頁面和動態互動

元件開發順序:自上而下 or 自下而上

App -> TodoList -> Todo -> AddTodo -> Footer

3.什麼是state

代表UI的完整且最小狀態集合

4.如何判斷

是否通過父元件props傳入?

是否不會隨著時間、互動操作變化?

是否可以通過其它state或props計算得到?

5.State的雙層含義

代表應用UI的所有狀態的集合

代表集合中的每一部分(待辦事項列表、新增輸入框文字、篩選條件)

6.分析State儲存位置

確定依賴state的每一個元件

如果某個state被多個元件依賴,尋找共同的父元件(狀態上移)

7.新增互動行為

藉助props,新增反向資料流

新增todo、修改todo狀態、過濾顯示

8.程式碼

src->index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';


ReactDOM.render(<App />, document.getElementById('root'));  

src->components->App.js

import React, { Component } from "react";
import AddTodo from "./AddTodo";
import TodoList from "./TodoList";
import Footer from "./Footer";

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      todos: [],
      filter: "all"
    };
    this.nextTodoId = 0;
  }

  render() {
    const todos = this.getVisibleTodos();
    const { filter } = this.state;
    return (
      <div>
        <AddTodo addTodo={this.addTodo} />
        <TodoList todos={todos} toggleTodo={this.toggleTodo} />
        <Footer
          filter={filter}
          setVisibilityFilter={this.setVisibilityFilter}
        />
      </div>
    );
  }

  getVisibleTodos = () => {
    const currentFilter = this.state.filter;
    return this.state.todos.filter(item => {
      if (currentFilter === "active") {
        return !item.completed;
      } else if (currentFilter === "completed") {
        return item.completed;
      } else {
        return true;
      }
    });
  };

  addTodo = text => {
    const todo = {
      id: this.nextTodoId++,
      text,
      completed: false
    };
    const newTodos = [todo, ...this.state.todos];
    this.setState({
      todos: newTodos
    });
  };

  toggleTodo = id => {
    const newTodos = this.state.todos.map(item => {
      return item.id === id ? { ...item, completed: !item.completed } : item;
    });
    this.setState({
      todos: newTodos
    });
  };

  setVisibilityFilter = filter => {
    this.setState({
      filter
    });
  };
}

export default App;  

src->components->TodoList.js

import React, { Component } from 'react';
import Todo from "./Todo";

class TodoList extends Component {
  render() {
    const {todos, toggleTodo} = this.props;
    return (
      <ul>
        {
          todos.map(todo => {
            return <Todo key={todo.id} {...todo} 
            onClick={() => {toggleTodo(todo.id)}}/>
          })
        }
      </ul>
    );
  }
}

export default TodoList;  

src->components->Todo.js

import React, { Component } from "react";

class Todo extends Component {
  render() {
    const { completed, text, onClick } = this.props;
    return (
      <li
        onClick={onClick}
        style={{
          textDecoration: completed ? "line-through" : "none"
        }}
      >
        {text}
      </li>
    );
  }
}

export default Todo;  

src->components->AddTodo.js

import React, { Component } from 'react';

class AddTodo extends Component {
  constructor(props) {
    super(props);
    this.state = {
      text: ''
    }
  }
  
  render() {
    return (
      <div>
        <input value={this.state.text} onChange={this.handleChange}/>
        <button onClick={this.handleClick}>Add</button>
      </div>
    );
  }

  handleChange = (e) => {
    this.setState({
      text: e.target.value
    })
  } 

  handleClick = () => {
    this.props.addTodo(this.state.text);
  }
}

export default AddTodo; 

src->components->Footer.js

import React, { Component } from "react";

class Footer extends Component {
  render() {
    const { filter, setVisibilityFilter } = this.props;
    return (
      <div>
        <span>Show:</span>
        <button
          disabled={filter === "all"}
          onClick={() => setVisibilityFilter("all")}
        >
          All
        </button>
        <button
          disabled={filter === "active"}
          onClick={() => setVisibilityFilter("active")}
        >
          Active
        </button>
        <button
          disabled={filter === "completed"}
          onClick={() => setVisibilityFilter("completed")}
        >
          Completed
        </button>
      </div>
    );
  }
}

export default Footer;

注:專案來自慕課網