前言:正在学习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;
注:项目来自慕课网