【重點突破】—— create-react-app&React元件化思想
前言:正在學習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;
注:專案來自慕課網