b站React禹哥版视频笔记-React应用(基于react脚手架)

前言

上一篇:React面向组件编程(下)
本篇内容:React应用(基于react脚手架)

一、初始化react脚手架

1.react脚手架:

1.xxx脚手架: 用来帮助程序员快速创建一个基于xxx库的模板项目

a.包含了所有需要的配置(语法检查、jsx编译、devServer…)
b.下载好了所有相关的依赖
c.可以直接运行一个简单效果

2.react提供了一个用于创建react项目的脚手架库: create-react-app
3.项目的整体技术架构为: react + webpack + es6 + eslint
4.使用脚手架开发的项目的特点: 模块化, 组件化, 工程化

2.创建项目并启动

  1. 全局安装:npm i -g create-react-app
  2. 切换到你想创建项目的目录下,使用命令:create-react-app xxx(项目名,比如,hello-react)
  3. 进入项目文件夹:cd hello-react
  4. 启动项目:yarn start或npm start
    注:若create-react-app安装失败,可以尝试更换npm源,更换成淘宝的,参考
    在这里插入图片描述
    在这里插入图片描述
    安装成功后:在这里插入图片描述
    启动项目:在这里插入图片描述
    会让你选择用哪个浏览器打开,成功的页面(即成功运行了react官方给的模板项目):

二、脚手架文件介绍

1.public

public文件一般存静态资源,比如页面、样式、公共的图片

以后写项目时,只有一个.html文件,也就是单页面应用(SPA)

favicon.icon ------ 网站页签图标
index.html -------- 主页面
logo192.png ------- logo图
logo512.png ------- logo图
manifest.json ----- 应用加壳的配置文件
robots.txt -------- 爬虫协议文件

2.src

App.js:定义了一个组件App
App.css:组件App的样式文件
App.test.js:测试App的,我们几乎不用
index.css:通用的样式
index.js:入口文件
logo.svg:logo图片
reportWebVitals.js:记录页面性能,里面用了web-vitals库
aetupTest.js:用于组件测试,里面用了第三方库web-vitals

三、一个简单的Hello组件

后缀同为.js,区分组件文件和普通js文件:
1.组件文件首字母大写,普通js文件首字母小写
2.把组件文件后缀改为.jsx

上图中的写法在App.js中引入组件时略显臃肿,下图中是另一种写法:

四、样式的模块化

当两个组件样式中有相同的className时,后引入的组件样式会覆盖掉之前的样式

  1. 把文件名改为index.module.css
  2. 引入css文件时:import hello from './index.module.css'
  3. 使用样式时:className={hello.title}

样式的模块化用的不是很多,一般用less的嵌套写法即可

五、vscode中react插件的安装

在vscode的插件市场中搜索react👇
在这里插入图片描述
比如,一些代码片段:
rcc:类式组件
rfc:函数式组件

六、组件化编码流程

tips:
①打开终端快捷键:ctrl + ~
②停止运行快捷键:ctrl + C

  1. 拆分组件: 拆分界面,抽取组件

  2. 实现静态组件: 使用组件实现静态页面效果

  3. 实现动态组件
    3.1 动态显示初始化数据

    3.1.1 数据类型
    3.1.2 数据名称
    3.1.2 保存在哪个组件?
    

    3.2 交互(从绑定事件监听开始)

七、组件的组合使用-TodoList案例

功能: 组件化实现此功能

  1. 显示所有todo列表
  2. 输入文本, 点击按钮显示到列表的首位, 并清除输入的文本

1.静态组件

  1. App.js中引入模块的顺序
    ①外部模块②自己的模块③样式文件
  2. 拆分List与Item时,先把List整个拆分,再在List里面拆分Item

2.动态初始化列表

数据存放在App的state中,传给子组件List:

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

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

把List中的数据批量传递给其子组件Item:

export default class List extends Component{
    render(){
        const {todos}=this.props;
        return (
            <ul className="todo-main">
                {
                    todos.map(todo=>{
                        // return <Item key={todo.id} id={todo.id} name={todo.name} done={todo.done}/>
                        return <Item key={todo.id} {...todo}/>  // 批量传递
                    })
                }
            </ul>
        )
    }
}

Item组件接收数据:

export default class Item extends Component {
  render() {
    const {name,done}=this.props
    return (
          <li>
            <label>
                <input type="checkbox" defaultChecked={done}/>
                <span>{name}</span>
            </label>
            <button className="btn btn-danger" style={{display:'none'}}>删除</button>
          </li>
    )
  }
}

3.添加todo

父给子传数据:props
子给父传数据:利用函数

比如子组件Header给父组件App传数据:

需要给input框绑定一个键盘事件:onKeyUp

专门生成唯一id的库:uuid
安装:yarn add uuid或者npm i uuid
但这个库有点大,不推荐,推荐nanoid

import React, { Component } from 'react'
import {nanoid} from 'nanoid'

import './index.css'

export default class Header extends Component {
  handleKeyUp=(event)=>{
    // 解构赋值获取keyCode,target
    const {keyCode,target}=event
    // 判断按下的是否为回车键
    if(keyCode!==13) return
    //添加的todo名字不能为空
    if(target.value.trim()===''){
      alert('输入不能为空!')
      return
    }
    // 准备好一个todo对象
    const todoObj={id:nanoid(),name:target.value,done:false}
    // 将todoObj传递给App
    this.props.addTodo(todoObj)
    // 清空输入
    target.value=''
  }
  render() {
    return (
      <div className="todo-header">
            <input onKeyUp={this.handleKeyUp} type="text" placeholder="请输入你的任务名称,按回车键确认"/>
      </div>
    )
  }
}

4.鼠标移入效果

鼠标悬浮在某一项上面时,该项高亮,且后面出现“删除”按钮

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

  handleMouse=(flag)=>{
    return ()=>{
      console.log(flag)
      this.setState({mouse:flag})
    }
  }

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

3.添加一个todo

根据勾选或者未勾选,更改状态里的值

tips:状态在哪里,操作状态的方法就在哪里
App给List传递props:

<List todos={todos} updateTodo={this.updateTodo}/>
// updateTodo用于更新一个todo对象
    updateTodo=(id,done)=>{
        // 获取状态中的todos
        const {todos}=this.state
        // 匹配 处理数据
        const newTodos=todos.map((todoObj)=>{
            if(todoObj.id===id) return {...todoObj,done}
            else return todoObj
        })
        this.setState({todos:newTodos})
    };

List给Item传递props:

return <Item key={todo.id} {...todo} updateTodo={updateTodo}/>

Item中的回调函数;

 // 勾选、取消勾选某一个todo的回调
  handleCheck=(id)=>{
    return (event)=>{
      // console.log(id,event.target.checked)
      this.props.updateTodo(id,event.target.checked)
    }
  }

4.对props进行限制

安装第三方库:yarn add prop-types
引入:import PropTypes from 'prop-types'
对传递的props进行类型以及必要性的限制:
Header组件中:

static propTypes={
    addTodo:PropTypes.func.isRequired
  }

List组件中:

static propTypes={
        todos:PropTypes.array.isRequired,
        updateTodo:PropTypes.func.isRequired
    }

5.删除一个todo

App组件中:

// deleteTodo用于删除一个todo对象
    // tips:不能用delete,因为delete是个关键字,用于删除对象中的某个属性
    deleteTodo=(id)=>{
        // 获取原来的todos
        const {todos}=this.state
        // 删除指定id的todo对象
        const newTodos=todos.filter((todoObj)=>{
            return todoObj.id!==id
        })
        // 更新状态
        this.setState({todos:newTodos})
    }

Item组件中:

// 删除一个todo的回调
  handleDelete=(id)=>{
    // console.log('通知App删除',id)
    // alert键只有确认
    if(window.confirm('确定删除吗?')){
      this.props.deleteTodo(id)
    }
  }

6.实现底部功能–Footer

tips:defaultChecked只在第一次时起作用
App组件给子组件Footer传递函数:

<Footer todos={todos} checkAllTodo={this.checkAllTodo} checkAllDone={this.checkAllDone}/>

在App组件中修改状态的值:

// checkAllTodo用于全选
    checkAllTodo=(done)=>{
        // 获取原来的todos
        const {todos}=this.state
        // 加工数据
        const newTodos=todos.map((todoObj)=>{
            return {...todoObj,done}
        })
        this.setState({todos:newTodos})
    }

    //checkAllDone用于清除已完成任务 
    checkAllDone=()=>{
        // 获取原来的todos
        const {todos}=this.state
        // 过滤数据
        const newTodos=todos.filter((todoObj)=>{
            //return todoObj.done===false
            return !todoObj.done
        })
        this.setState({todos:newTodos})
    }

子组件Footer调用父组件中的函数:

export default class Footer extends Component {
  // 全选checkbox的回调
  handleCheckAll=(event)=>{
    this.props.checkAllTodo(event.target.checked)
  }

  // 清除已完成任务的回调
  handleCheckAllDone=()=>{
    this.props.checkAllDone()
  }
  
  render() {
    const {todos}=this.props
    // 已完成的个数
    const doneCount=todos.reduce((pre,todo)=>{return pre + (todo.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 className="btn btn-danger" onClick={this.handleCheckAllDone}>清除已完成任务</button>
        </div>
    )
  }
}

7.总结TodoList案例

  1. 动态初始化列表,如何确定将数据放在哪个组件的state中?
    某个组件使用:放在其自身的state中
    某些组件使用:放在它们共同的父组件的state中(官方称此操作为状态提升)
  2. 关于父子组件之间通信:
    父–>子传递数据:通过props
    子–>父传递数据:通过props,要求父提前给子传递一个函数
  3. 注意defaultCheckedchecked的区别,类似的还有defaultValuevalue
  4. 状态在哪里,操作状态的方法就在哪里

写在后面

这周的进度比较慢,今天已经周六了,原计划明天看到p100,现在才到p65
因为从周一到周三调了毕设的代码,现在也算跑通了
这两天要赶赶进度了
下一篇是第四章的内容:React ajax

CSDN博客之星涵盖了各个领域的优秀博主,他们的博客具有很高的影响力和专业性。以下是CSDN博客之星领域前十的简要介绍: 1. 人工智能领域:博主通过深入研究人工智能领域的最新技术和应用,为读者提供了深度学习、机器学习和自然语言处理等方面的知识和经验分享。 2. 大数据领域:这些博主关注数据的采集、存储、处理和分析等方面,为企业和研究机构提供大数据解决方案和案例分析,推动了大数据技术的发展和应用。 3. 嵌入式领域:博主将嵌入式系统的设计、开发和调试等方面的知识进行了深入剖析,展示了嵌入式系统在汽车、智能家居和物联网等领域的应用。 4. 前端开发领域:这些博主关注前端开发的最新技术和趋势,他们分享了HTML/CSS、JavaScript前端框架等方面的教程和案例,为前端开发者提供了宝贵的参考和学习资源。 5. 后端开发领域:这些博主专注于后端开发技术,包括Java、Python、Go和Ruby等编程语言的应用和开发框架的使用,为开发者提供了实践经验和技术分享。 6. 移动开发领域:这些博主关注移动应用开发的最新趋势和技术,分享了iOS、Android和React Native等平台的开发经验和解决方案,为移动开发者提供了有益的指导和教程。 7. 云计算领域:这些博主研究了云计算技术的最新进展和应用案例,包括云平台的搭建、容器技术和虚拟化等方面,为企业和个人提供了云计算解决方案和最佳实践。 8. 安全领域:这些博主关注网络安全和信息安全的最新动态和技术,分享了渗透测试、加密算法和安全工具的使用方法和原理,为企业和网络从业者提供了安全防护和实战的建议。 9. 数据库领域:这些博主专注于数据库技术的研究和应用,包括关系数据库和NoSQL数据库的比较、优化和应用案例,为开发者和DBA提供了有关数据库设计和管理的专业知识。 10. IT管理领域:博主在信息技术管理方面具有丰富经验,分享了项目管理、IT服务管理和IT战略规划等方面的知识和经验,为企业和IT从业者提供了管理方面的指导和思路。 总之,CSDN博客之星领域前十的博主们在各自的领域里,通过博客的方式分享了宝贵的技术和经验,为读者提供了学习和成长的机会。他们的贡献推动了相应领域的发展和创新。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值