[尚硅谷React笔记]——第3章 React应用(基于React脚手架)

目录:

  1. react脚手架
  2. 创建项目并启动
  3. react脚手架项目结构
  4. 一个简单的Hello组件
  5. 样式的模块化
  6. 功能界面的组件化编码流程(通用)
  7. 组件的组合使用-TodoList

1.react脚手架

  1. xxx脚手架: 用来帮助程序员快速创建一个基于xxx库的模板项目
    1. 包含了所有需要的配置(语法检查、jsx编译、devServer...)
    2. 下载好了所有相关的依赖
    3. 可以直接运行一个简单效果
  2. react提供了一个用于创建react项目的脚手架库: create-react-app
  3. 项目的整体技术架构为: react + webpack + es6 + eslint
  4. 使用脚手架开发的项目的特点: 模块化, 组件化, 工程化

2.创建项目并启动

  1. 全局安装:npm i -g create-react-app
  2. 切换到想创项目的目录,使用命令:create-react-app hello-react
  3. 进入项目文件夹:cd hello-react
  4. 启动项目:npm start

3.react脚手架项目结构

public ---- 静态资源文件夹

favicon.icon ------ 网站页签图标

index.html -------- 主页面

logo192.png ------- logo图

logo512.png ------- logo图

manifest.json ----- 应用加壳的配置文件

robots.txt -------- 爬虫协议文件

src ---- 源码文件夹

App.css -------- App组件的样式

App.js --------- App 组件

App.test.js ---- 用于给App做测试

index.css ------ 样式

index.js ------- 入口文件

logo.svg ------- logo图

reportWebVitals.js --- 页面性能分析文件(需要web-vitals库的支持)

setupTests.js ---- 组件单元测试的文件(需要jest-dom库的支持)

4.一个简单的Hello组件

Hello.jsx

bash 复制代码
import React, {Component} from 'react'
import './Hello.css'

export default class Hello extends Component {
    render() {
        return <h2 className="title">hello,react!</h2>
    }
}

Hello.css

bash 复制代码
.title {
    background-color: orange;
}

Welcome.jsx

bash 复制代码
import React, {Component} from "react";
import './Welcome.css'

export default class Welcome extends Component {
    render() {
        return <h2 className="demo">welcome</h2>
    }
}

Welcome.css

bash 复制代码
.demo {
    background-color: skyblue;
}

App.js

bash 复制代码
import React from 'react'
import Hello from "./components/Hello/Hello";
import Welcome from "./components/Welcome/Welcome";

export default class App extends React.Component {
    render() {
        return (
            <div>
                <Hello></Hello>
                <Welcome></Welcome>
            </div>
        )
    }
}

index.js

bash 复制代码
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App/>);

运行结果:

5.样式的模块化

Hello.jsx

bash 复制代码
import React, {Component} from 'react'
import hellocss from './Hello.module.css'

export default class Hello extends Component {
    render() {
        return <h2 className={hellocss.title}>hello,react!</h2>
    }
}

Hello.module.css

bash 复制代码
.title {
    background-color: orange;
}

Welcome.jsx

bash 复制代码
import React, {Component} from "react";
import welcomecss from './Welcome.module.css'

export default class Welcome extends Component {
    render() {
        return <h2 className={welcomecss.title}>welcome</h2>
    }
}

Welcome.module.css

bash 复制代码
.title {
    background-color: skyblue;
}

运行结果:

6.功能界面的组件化编码流程(通用)

  1. 拆分组件: 拆分界面,抽取组件
  2. 实现静态组件: 使用组件实现静态页面效果
  3. 实现动态组件
    1. 动态显示初始化数据
      1. 数据类型
      2. 数据名称
      3. 保存在哪个组件?
    2. 交互(从绑定事件监听开始)

7.组件的组合使用-TodoList

todoList案例相关知识点

  1. 拆分组件、实现静态组件,注意: className、style的写法
  2. 动态初始化列表,如何确定将数据放在哪个组件的state中?
    1. 某个组件使用放在自身的state中
    2. 某些组件使用:放在他们共同的父组件state中(官方称此操作为:状态提升
  3. 关于父子之间通信:
    1. 【父组件】给【子组件】传递数据:通过props传递
    2. 【子组件】给【父组件】传递数据:通过props传递,要求父提前给子传递
  4. 注意defaultchecked 和 checked的区别,类似的还有: defaultValue 和 value
  5. 状态在哪里,操作状态的方法就在哪里

Footer.css

bash 复制代码
/*footer*/
.todo-footer {
    height: 40px;
    line-height: 40px;
    padding-left: 6px;
    margin-top: 5px;
}

.todo-footer label {
    display: inline-block;
    margin-right: 20px;
    cursor: pointer;
}

.todo-footer label input {
    position: relative;
    top: -1px;
    vertical-align: middle;
    margin-right: 5px;
}

.todo-footer button {
    float: right;
    margin-top: 5px;
}

Footer.jsx

bash 复制代码
import React, {Component} from 'react';
import './Footer.css'

class Footer extends Component {
    handleCheckAll = (event) => {
        this.props.checkAllTodo(event.target.checked)
    }
    handleClearAllDone = () => {
        this.props.clearAllDone()
    }


    render() {
        const {todos} = this.props
        const doneCount = todos.reduce((pre, current) => {
            return pre + (current.done ? 1 : 0)
        }, 0)
        const total = todos.length
        return (
            <div className="todo-footer">
                <label>
                    <input type="checkbox" onChange={this.handleCheckAll}
                           checked={doneCount === total && total !== 0 ? true : false}/>
                </label>
                <span>
                    <span>已完成{doneCount}</span> / 全部{total}
                </span>
                <button onClick={this.handleClearAllDone} className="btn btn-danger">清除已完成任务</button>
            </div>
        );
    }
}

export default Footer;

Header.css

bash 复制代码
/*header*/
.todo-header input {
    width: 560px;
    height: 28px;
    font-size: 14px;
    border: 1px solid #ccc;
    border-radius: 4px;
    padding: 4px 7px;
}

.todo-header input:focus {
    outline: none;
    border-color: rgba(82, 168, 236, 0.8);
    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
}

Header.jsx

bash 复制代码
import React, {Component} from 'react';
import PropTypes from 'prop-types'
import {nanoid} from "nanoid";
import './Header.css'

class Header extends Component {
    static propTypes = {
        addTodo: PropTypes.func.isRequired
    }

    handleKeyUp = (event) => {
        const {keyCode, target} = event
        if (keyCode != 13) return
        if (target.value.trim() == '') {
            alert('输入不能为空')
            return;
        }
        const todoObj = {id: nanoid(), name: target.value, done: false}
        this.props.addTodo(todoObj)

        target.value = ''
    }

    render() {
        return (
            <div className="todo-header">
                <input onKeyUp={this.handleKeyUp} type="text" placeholder="请输入你的任务名称,按回车键确认"/>
            </div>
        );
    }
}

export default Header;

Item.css

bash 复制代码
/*item*/
li {
    list-style: none;
    height: 36px;
    line-height: 36px;
    padding: 0 5px;
    border-bottom: 1px solid #ddd;
}

li label {
    float: left;
    cursor: pointer;
}

li label li input {
    vertical-align: middle;
    margin-right: 6px;
    position: relative;
    top: -1px;
}

li button {
    float: right;
    display: none;
    margin-top: 3px;
}

li:before {
    content: initial;
}

li:last-child {
    border-bottom: none;
}

Item.jsx

bash 复制代码
import React, {Component} from 'react';
import './Item.css'

class Item extends Component {
    state = {mouse: false}

    handelMouse = (flag) => {
        return () => {
            this.setState({mouse: flag})
        }
    }

    handleCheck = (id) => {
        return (event) => {
            this.props.updateTodo(id, event.target.checked)
        }
    }

    handleDelete = (id) => {
        if (window.confirm('确定删除吗?')) {
            this.props.deleteTodo(id)
        }
    }

    render() {
        const {id, name, done} = this.props
        const {mouse} = this.state
        return (
            <li style={{backgroundColor: mouse ? '#ddd' : 'white'}} onMouseEnter={this.handelMouse(true)}
                onMouseLeave={this.handelMouse(false)}>
                <label>
                    <input type="checkbox" checked={done} onChange={this.handleCheck(id)}/>
                    <span>{name}</span>
                </label>
                <button onClick={() => {
                    this.handleDelete(id)
                }}
                        className="btn btn-danger"
                        style={{display: mouse ? 'block' : 'none'}}>删除
                </button>
            </li>
        );
    }
}

export default Item;

List.css

bash 复制代码
/*main*/
.todo-main {
    margin-left: 0px;
    border: 1px solid #ddd;
    border-radius: 2px;
    padding: 0px;
}

.todo-empty {
    height: 40px;
    line-height: 40px;
    border: 1px solid #ddd;
    border-radius: 2px;
    padding-left: 5px;
    margin-top: 10px;
}

List.jsx

bash 复制代码
import React, {Component} from 'react';
import PropTypes from "prop-types";
import Item from "../Item/Item";
import './List.css'


class List extends Component {
    static propTypes = {
        todos: PropTypes.array.isRequired,
        updateTodo: PropTypes.func.isRequired,
        deleteTodo: PropTypes.func.isRequired
    }

    render() {
        const {todos, updateTodo, deleteTodo} = this.props
        return (
            <ul className="todo-main">
                {
                    todos.map((todo) => {
                        return <Item key={todo.id} {...todo} updateTodo={updateTodo} deleteTodo={deleteTodo}></Item>
                    })
                }
            </ul>
        );
    }
}

export default List;

App.css

bash 复制代码
/*base*/
body {
    background: #fff;
}

.btn {
    display: inline-block;
    padding: 4px 12px;
    margin-bottom: 0;
    font-size: 14px;
    line-height: 20px;
    text-align: center;
    vertical-align: middle;
    cursor: pointer;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
    border-radius: 4px;
}

.btn-danger {
    color: #fff;
    background-color: #da4f49;
    border: 1px solid #bd362f;
}

.btn-danger:hover {
    color: #fff;
    background-color: #bd362f;
}

.btn:focus {
    outline: none;
}

.todo-container {
    width: 600px;
    margin: 0 auto;
}

.todo-container .todo-wrap {
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 5px;
}

App.js

bash 复制代码
import React, {Component} from 'react';
import './App.css'
import Header from "./components/Header/Header";
import Footer from "./components/Footer/Footer";
import List from "./components/List/List";

class App extends Component {
    //初始化状态
    state = {
        todos: [
            {id: '001', name: '吃饭', done: true},
            {id: '002', name: '睡觉', done: true},
            {id: '003', name: '打代码', done: false},
            {id: '004', name: '逛街', done: true},
        ]
    }

    addTodo = (todoObj) => {
        const {todos} = this.state
        const newTodos = [todoObj, ...todos]
        this.setState({todos: newTodos})
    }

    updateTodo = (id, done) => {
        const {todos} = this.state
        const newTodos = todos.map((todoObj) => {
            if (todoObj.id === id) {
                return {...todoObj, done: done}
            } else {
                return todoObj
            }
        })

        this.setState({todos: newTodos})
    }

    deleteTodo = (id) => {
        const {todos} = this.state
        const newTodos = todos.filter((todoObj) => {
            return todoObj.id !== id
        })
        this.setState({todos: newTodos})
    }

    checkAllTodo = (done) => {
        const {todos} = this.state
        const newTodos = todos.map((todoObj) => {
            return {...todoObj, done: done}
        })
        this.setState({todos: newTodos})
    }

    clearAllDone = () => {
        const {todos} = this.state
        const newTodos = todos.filter((todoObj) => {
            return !todoObj.done
        })
        this.setState({todos: newTodos})
    }

    render() {
        return (
            <div className="todo-container">
                <div className="todo-wrap">
                    <Header addTodo={this.addTodo}></Header>
                    <List todos={this.state.todos} updateTodo={this.updateTodo} deleteTodo={this.deleteTodo}></List>
                    <Footer todos={this.state.todos}
                            checkAllTodo={this.checkAllTodo}
                            clearAllDone={this.clearAllDone}>
                    </Footer>
                </div>
            </div>
        );
    }
}

export default App;

index.js

bash 复制代码
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App/>);

项目结构:

''

运行结果:

相关推荐
若川35 分钟前
Taro 源码揭秘:10. Taro 到底是怎样转换成小程序文件的?
前端·javascript·react.js
LuH11241 小时前
【论文阅读笔记】IC-Light
论文阅读·笔记
是小菜呀!1 小时前
实验四 触发器
笔记
IT女孩儿1 小时前
JavaScript--WebAPI查缺补漏(二)
开发语言·前端·javascript·html·ecmascript
悲伤小伞1 小时前
C++_数据结构_详解二叉搜索树
c语言·数据结构·c++·笔记·算法
灰太狼不爱写代码4 小时前
CUDA11.4版本的Pytorch下载
人工智能·pytorch·笔记·python·学习
@解忧杂货铺5 小时前
前端vue如何实现数字框中通过鼠标滚轮上下滚动增减数字
前端·javascript·vue.js
Aileen_0v010 小时前
【AI驱动的数据结构:包装类的艺术与科学】
linux·数据结构·人工智能·笔记·网络协议·tcp/ip·whisper
真的很上进10 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
Rinai_R12 小时前
计算机组成原理的学习笔记(7)-- 存储器·其二 容量扩展/多模块存储系统/外存/Cache/虚拟存储器
笔记·物联网·学习