欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

01_初入react_react学习笔记

程序员文章站 2022-03-15 19:16:32
...

文章目录

JSX

1.简介

  • 全称: JavaScript XML
  • react定义的一种类似于XML的JS扩展语法: XML+JS
作用
  • 用来创建react虚拟DOM(元素)对象

    a. var ele = <h1>Hello JSX!</h1>

    b. 注意1: 它不是字符串, 也不是HTML/XML标签

    c. 注意2: 它最终产生的就是一个JS对象

    d. 标签名任意: HTML标签或其它标签

    e. 标签属性任意: HTML标签属性或其它

基本语法规则

a. 遇到 <开头的代码, 以标签的语法解析: html同名标签转换为html同名元素, 其它标签需要特别解析

b. 遇到以 { 开头的代码,以JS语法解析: 标签中的js代码必须用{ }包含

babel.js的作用

a. 浏览器不能直接解析JSX代码, 需要babel转译为纯JS的代码才能运行

b. 只要用了JSX,都要加上type=“text/babel”, 声明需要babel来处理

2.创建虚拟DOM

前置

  <div id="test1"></div>
  <div id="test2"></div>
  <script type="text/javascript" src="../js/react.development.js"></script>
  <script type="text/javascript" src="../js/react-dom.development.js"></script>
  <script type="text/javascript" src="../js/babel.min.js"></script>
1.纯JS(一般不用)

var element = React.createElement(‘h1’, {id:‘myTitle’},‘hello’)

<script type="text/javascript">
    // 1. 创建虚拟DOM
    /*方式一: 纯JS(一般不用)创建虚拟DOM元素对象*/
    const msg = 'I Like You!'
    const myId = 'Atguigu'
    const vDOM1 = React.createElement('h2', {id: myId}, msg.toUpperCase())//msg转为大写
    // 2. 渲染到真实页面
    const domContainer = document.getElementById('test1')
    // debugger
    ReactDOM.render(vDOM1, domContainer)
 </script>
2.JSX创建

<h1 id=‘myTitle’>{title}</h1>

<script type="text/babel">
  // 1. 创建虚拟DOM
  /*方式二: JSX创建虚拟DOM元素对象*/
  const vDOM2 = <h3 id={myId.toUpperCase()}>{msg.toLowerCase()}</h3>
  // debugger
  // 2. 渲染到真实页面
  ReactDOM.render(vDOM2, document.getElementById('test2'))
</script>

3.debugger

在代码中写debugger可以起到断点作用进行调试

4.真实DOM和虚拟DOM

//虚拟dom
const vDOM1 = React.createElement('h2', {id: myId}, msg)
//真实dom
cponst rDOM1 = document.getElementById('test1')

前者比较轻,后者比较重,一旦修改页面刷新,前者只有重新渲染的时候才刷新

真实dom属性比虚拟dom多

虚拟DOM对象最终都会被React转换为真实的DOM

我们编码时基本只需要操作react的虚拟DOM相关数据, react会转换为真实DOM变化而更新界面

5. 渲染虚拟DOM(元素)

  1. 语法: ReactDOM.render(virtualDOM, containerDOM)

  2. 作用: 将虚拟DOM元素渲染到页面中的真实容器DOM中显示

  3. 参数说明

a. 参数一: 纯js或jsx创建的虚拟dom对象

b. 参数二: 用来包含虚拟DOM元素的真实dom元素对象(一般是一个div)

exercise:动态展示列表数据(数据数组–>标签数组)

技术点:
1). 使用JSX创建虚拟DOM
2). React能自动遍历显示数组中所有的元素
3). array.map()的使用

<body>
  <h2>前端JS框架列表</h2>
  <div id="example1"></div>
  <div id="example2"></div>

  <script type="text/javascript" src="../js/react.development.js"></script>
  <script type="text/javascript" src="../js/react-dom.development.js"></script>
  <script type="text/javascript" src="../js/babel.min.js"></script>
</body>
<script type="text/babel">
    /*
     功能: 动态展示列表数据
     */

    // 数据的数组
    var names = ['jquery', 'zeptoo', 'angular', 'react全家桶', 'vue全家桶']

    // 数据的数组-->标签的数组
    //方法1
    var lis = []
    names.forEach((name, index) => lis.push(<li key={index}>{name}</li>))
    // 创建虚拟DOM
    const ul = <ul>{lis}</ul>
    // 渲染虚拟DOM
    ReactDOM.render(ul, document.getElementById('example1'))
    //方法2
    const ul2 = <ul>{
      names.map((name, index) => <li key={index}>{name}</li>)
    }</ul>
    ReactDOM.render(ul2, document.getElementById('example2'))
</script>
js新函数map()

map() 方法返回一个数组,数组中的元素为原始数组元素调用函数处理后的值。

map() 方法按照原始数组元素顺序依次处理元素。

注意: map() 不会对空数组进行检测。

注意: map() 不会改变原始数组

var array1 = [1, 4, 9, 16];
 
const map1 = array1.map(x => {
    if (x == 4) {
        return x * 2;
    }
    return x;
});

这里注意箭头函数有两种格式:
1.只包含一个表达式,这时花括号和return都省略了。
2.包含多条语句,这时花括号和return都不能省略。

js新函数onblur

onblur 事件会在对象失去焦点时发生。

<html>
<head>
<script type="text/javascript">
function upperCase()
{
var x=document.getElementById("fname").value
document.getElementById("fname").value=x.toUpperCase()
}
</script>
</head>

<body>

输入您的姓名:
<input type="text" id="fname" onblur="upperCase()" />

</body>
</html

面向组件编程

1.步骤

<div id="example1"></div>
<div id="example2"></div>
1.定义组件
  • 工厂函数组件(简单组件,没有状态的组件)直接调用方法 有state就不能用工厂模式
function MyComponent () {
  return <h2>工厂函数组件(简单组件)</h2>
}
  • ES6组件(复杂组件)先创建实例,实例调用render方法
class MyComponent2 extends React.Component {
  render () {
    console.log(this) // MyComponent2的实例对象
    return <h2>ES6类组件(复杂组件)</h2>
  }
2.渲染组件标签
    ReactDOM.render(<MyComponent />, document.getElementById('example1'))
    ReactDOM.render(<MyComponent2 />, document.getElementById('example2'))
3.注意
  1. 组件名必须首字母大写

  2. 虚拟DOM元素只能有一个根元素

  3. 虚拟DOM元素必须有结束标签

4.ReactDOM.render()渲染组件标签的基本流程
  • React内部会创建组件实例对象/调用组件函数, 得到虚拟DOM对象
  • 将虚拟DOM并解析为真实DOM
  • 插入到指定的页面元素内部

2.组件三大属性

2.1 state
理解
  1. state是组件对象最重要的属性, 值是对象(可以包含多个数据)

  2. 组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)

编码操作
  1. 初始化状态:
 constructor (props) {
  super(props)
  this.state = {
   stateProp1 : value1,
   stateProp2 : value2
  }
 }
  1. 读取某个状态值
 this.state.statePropertyName
  1. 更新状态---->组件界面更新
 this.setState({
  stateProp1 : value1,
  stateProp2 : value2
 })

例子:

<script type="text/babel">
  /*
  需求: 自定义组件, 功能说明如下
    1. 显示h2标题, 初始文本为: 你喜欢我
    2. 点击标题更新为: 我喜欢你
  */
  class Like extends React.Component{

    constructor(props) {
      super(props);
      //初始化状态
      this.state={
          isLikeMe:false
      }
      //将新增方法的this绑定为组件对象
      //bind返回一个新函数,因此要将新函数指向handleclick()
      this.handleClick = this.handleClick.bind(this)
    }
    //新增类方法,this默认是undefined
    handleClick(){
      //读取状态并取反
      const isLikeMe = !this.state.isLikeMe
      //更新状态
      this.setState({isLikeMe:isLikeMe})
    }

    render(){
      //读取状态
      const {isLikeMe}=this.state
          return <h2 onClick={this.handleClick}>{isLikeMe? '你喜欢我':'我喜欢你'}</h2>
    }
  }
  ReactDOM.render(<Like/>,document.getElementById('example'))
</script>
2.2 props
理解
  1. 每个组件对象都会有props(properties的简写)属性

  2. 组件标签的所有属性都保存在props中

  • class 属性需要写成 className ,for 属性需要写成 htmlFor ,这是因为 class 和 for 是 JavaScript 的保留字。

  • 直接在标签上使用style属性时,要写成style={{}}是两个大括号,外层大括号是告知jsx这里是js语法,和真实DOM不同的是,属性值不能是字符串而必须为对象,需要注意的是属性名同样需要驼峰命名法。即margin-top要写成marginTop。

  • this.props.children 不要children作为把对象的属性名。因为this.props.children获取的该标签下的所有子标签。this.props.children 的值有三种可能:如果当前组件没有子节点,它就是 undefined ;如果有一个子节点,数据类型是 object ;如果有多个子节点,数据类型就是 array 。所以,处理 this.props.children 的时候要小心。官方建议使用React.Children.map来遍历子节点,而不用担心数据类型

作用
  1. 通过标签属性从组件外向组件内传递变化的数据

  2. 注意: 组件内部不要修改props数据

编码操作
  1. 内部读取某个属性值
this.props.propertyName
  1. 对props中的属性值进行类型限制必要性限制(已过时)
Person.propTypes = {
name: React.PropTypes.string.isRequired,
age: React.PropTypes.number.isRequired
}

新版本需要引入包prop-types.js

  1. 扩展属性: 将对象的所有属性通过props传递
… 的作用

1.打包

function fn(…as){} fn(1,2,3)

as就是数组类型

2.解包

const arr1 = [1,2,3]

const arr2 =[6,…arr1,9] 相当于替换为[6,1,2,3,9]

<Person {...person}/
  1. 默认属性值
Person.defaultProps = {
name: 'Mary'
}
  1. 组件类的构造函数
constructor (props) {
super(props)
console.log(props) // 查看所有属性
}

例子

//1.工厂方法
<script type="text/babel">

    /*
  需求: 自定义用来显示一个人员信息的组件, 效果如页面. 说明
    1). 如果性别没有指定, 默认为男
    2). 如果年龄没有指定, 默认为18
    */

    //1.定义组件
    function Person(props) {
        return (
            <ul>
                <li>姓名:{props.name}</li>
                <li>年龄:{props.age}</li>
                <li>性别:{props.sex}</li>
            </ul>
        )
    }

    //指定属性默认值
    Person.defaultProps = {
      sex:'男',
      age:18
    }

    //指定属性的类型和必要性
    Person.propTypes = {
      name:PropTypes.string.isRequired,
      sex: PropTypes.string,
      age: PropTypes.number
    }

    //2.渲染组件标签
    const p1={
      name:"Tom",
      age:18,
      sex:'女'
    }
    const p2 = {
      name:"Mary"
    }

//  ReactDOM.render(<Person name={p1.name} age={p1.age} sex={p1.sex}/>, document.getElementById('example1'));
    ReactDOM.render(<Person {...p1}/>, document.getElementById('example1'));

    ReactDOM.render(<Person name={p2.name}/>, document.getElementById('example2'))
</script>
//2.ES6组件
<script type="text/babel">

  /*
需求: 自定义用来显示一个人员信息的组件, 效果如页面. 说明
  1). 如果性别没有指定, 默认为男
  2). 如果年龄没有指定, 默认为18
  */

  //1. 定义组件类
  class Person extends React.Component {
    render() {
      console.log(this)
      return (
        <ul>
          <li>姓名: {this.props.name}</li>
          <li>性别: {this.props.sex}</li>
          <li>年龄: {this.props.age}</li>
        </ul>
      )
    }
  }
  // 对标签属性进行限制
  Person.propTypes = {
    name: PropTypes.string.isRequired,
    sex: PropTypes.string,
    age: PropTypes.number
  }
  // 指定属性的默认值
  Person.defaultProps = {
    sex: '男',
    age: 18
  }

  //2. 渲染组件标签
  const person = {
    name: 'Tom',
    sex: '女',
    age: 18
  }
  ReactDOM.render(<Person {...person}/>, document.getElementById('example1'))
  const person2 = {
    myName: 'JACK',
    age: 17
  }
  ReactDOM.render(<Person name={person2.myName} age={person2.age}/>,
    document.getElementById('example2'))
</script>
2.3 refs与事件处理
理解
  1. 组件内的标签都可以定义ref属性来标识自己

a. <input type=“text” ref={input => this.msgInput = input}/>,this.msginput就相当于是这个input标签了

b. 回调函数在组件初始化渲染完或卸载时自动调用

  1. 在组件中可以通过this.msgInput来得到对应的真实DOM元素

  2. 作用: 通过ref获取组件内容特定标签对象, 进行读取其相关数据

事件处理
  1. 通过onXxx属性指定组件的事件处理函数(注意大小写)

a. React使用的是自定义(合成)事件, 而不是使用的原生DOM事件

b. React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)

  1. 通过event.target得到发生事件的DOM元素对象
<input onFocus={this.handleClick}/>
handleFocus(event) {
event.target //返回input对象
}
编码操作
  <script type="text/babel">
    /*
    需求: 自定义组件, 功能说明如下:
      1. 界面如果页面所示
      2. 点击按钮, 提示第一个输入框中的值
      3. 当第2个输入框失去焦点时, 提示这个输入框中的值
   */
    //定义组件
    class MyComponent extends React.Component {
      constructor(props) {
        super(props) // 调用父类(Component)的构造函数
        //console.log(this)
        // 将自定义的函数强制绑定为组件对象
        this.handleClick = this.handleClick.bind(this) // 将返回函数中的this强制绑定为指定的对象, 并没有改变原来的函数中的this
        this.handleblur = this.handleblur.bind(this)
      }
      // 自定义的方法中的this默认为null
      handleClick () {
        // alert(this) //this默认是null, 而不是组件对象
        // 得到绑定在当前组件对象上的input的值
        alert(this.msgInput.value)
      }
      handleBlur (event) {
        alert(event.target.value)
      }
      render () {
        return (
          <div>
            <input type="text" ref={input => this.msgInput = input}/>{' '}
            <button onClick={this.handleClick}>提示输入数据</button>{' '}
            <input type="text" placeholder="失去焦点提示数据" onBlur={this.handleBlur}/>
          </div>
        )
      }
    }
    // 渲染组件标签
    ReactDOM.render(<MyComponent />, document.getElementById('example'))
  </script>
注意
  1. 组件内置的方法中的this为组件对象

  2. 在组件类中自定义的方法中this为null

a. 强制绑定this: 通过函数对象的bind()

b. 箭头函数(ES6模块化编码时才能使用)

3. 组件组合

功能界面的组件化编码流程(无比重要)
  1. 拆分组件: 拆分界面,抽取组件

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

  3. 实现动态组件

a. 动态显示初始化数据

b. 交互功能(从绑定事件监听开始)

编码操作
<script type="text/babel">
    /*
    * 问题:数据保存在哪个组件内?
    *     看数据是某个组件需要(给它)还是某些组件需要(给共同的父亲)
    * 问题2:需要在子组件中改变父组件的状态?
    *     子组件中不能直接改变父组件的状态
    *     状态在哪个组件,更新状态的行为(方法)就应该定义在哪个组件
    *     解决:父组件定义函数,传递给子组件,子组件调用
    * */

    class App extends React.Component{
      constructor(props) {
        super(props);
        this.state = {
          //初始化状态
          todos: ['吃饭', '睡觉', 'code'],
          //test:['1','2','3']
        }
        this.addTodo = this.addTodo.bind(this)
        }

      addTodo(todo){
        const {todos} = this.state //相当于 const todos = this.state.todos {}是解构语法方便取值
        todos.unshift(todo)
        //更新状态
        this.setState({todos})
        //不能这么写
        // this.state.todos.unshift(todo)
        //更新状态
        //this.setState(this.state) 不会报错,但是这个相当于把原来的state在传给setState()有副作用
        //正确的应该是建立新state传进去
        //this.setState({this.state.todos})这种是新state但是就只有todos一个属性了,原state里其他属性就没了
        //所以要用解构语法(如下),顺序没要求
        //this.setState({todos,...this.state})

      }
      render(){
        return(
          <div>
            <h1>Simple To Do List</h1>
            <Add count={this.state.todos.length} addTodo = {this.addTodo}/>
            <List todos={this.state.todos}/>
          </div>
        )
      }
    }

    class Add extends React.Component{

      constructor(props) {
        super(props);

        this.add = this.add.bind(this)
      }

      add(addTodo){
//      1.读取输入的数据
        const todo = this.todoInput.value.trim()
//      2.检查合法性
        if(!todo) {
          return
        }
//      3.添加
        this.props.addTodo(todo)
//      4.清除输入
        this.todoInput.value = ''
      }

      render(){
        return(
          <div>
            <input type="text" ref={ myInput => this.todoInput = myInput}/>
            <button onClick={this.add}>add #{this.props.count+1}</button>
          </div>
        )
      }
    }

    class List extends React.Component{
      render(){
        return(
          <ul>
            {
              this.props.todos.map((value,index)=><li key={index}>{value}</li>)
          //或者this.props.todos.map((value,index)=>{return <li key={index}>{value}</li>})
          //为什么加了{}就要用return,因为{}默认是一个函数体
            }
          </ul>
        )
      }
    }

    Add.propTypes = {
        count:PropTypes.number.isRequired,
      addTodo:PropTypes.func.isRequired
    }

    List.propTypes = {
       todos:PropTypes.array.isRequired
    }

    ReactDOM.render(<App/>, document.getElementById('example'))
  </script>

4. 组件收集表单数据

理解
  • 问题: 在react应用中, 如何收集表单输入数据

  • 包含表单的组件分类

    • 受控组件: 表单项输入数据能自动收集成状态 如下面的name 简单一些
    • 非受控组件: 需要时才手动读取表单输入框中的数据 如下面的pwd 自动收集,建议用这个
编码操作
需求: 自定义包含表单的组件
  1. 输入用户名密码后, 点击登陆提示输入信息
  3. 不提交表单
<script type="text/babel">
  /*
  需求: 自定义包含表单的组件
    1. 界面如下所示
    2. 输入用户名密码后, 点击登陆提示输入信息
    3. 不提交表单
  */
  class LoginFrom extends React.Component{

    constructor(props) {
      super(props);

      //初始化状态
      this.state = {
        pwd:''
      }

      this.handleSubmit = this.handleSubmit.bind(this)
      this.handleChange = this.handleChange.bind(this)
    }

    handleSubmit(event){
      const name = this.nameInput.value
      //或者 const{value} = this,nameInput
      const {pwd} = this.state
      alert(`准备提交的用户名为:${name},密码为:${pwd}`)

      //阻止事件的默认行为(提交)
      event.preventDefault()
    }

    handleChange(event){
      //读取输入的值,
      const pwd = event.target.value
      //更新pwd状态
      //或者this.setState({pwd:event.target.value})
      this.setState({pwd})
    }
    //方法1:用ref 受控组件
    //方法2:用value和state以及onChange,原生js中onChange是失去焦点调用, 非受控组件
    //       这里我们用的是自定义dom事件,是value一改变就会调用
    render(){
      return(
        <form action="/test" onSubmit={this.handleSubmit}>

          用户名:  <input type="text" ref={input =>this.nameInput = input }/>

          密码:    <input type="password" value={this.state.pwd} onChange={this.handleChange}/>
          <input type="submit" value="登录"/>
        </form>
      )
    }
  }
ReactDOM.render(<LoginFrom/>, document.getElementById('example'))
</script>

5.组件生命周期

01_初入react_react学习笔记

理解
  1. 组件对象从创建到死亡它会经历特定的生命周期阶段

  2. React组件对象包含一系列的勾子函数(生命周期回调函数), 在生命周期特定时刻回调

  3. 我们在定义组件时, 可以重写特定的生命周期回调函数, 做特定的工作

生命周期流程图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4n8vkl6U-1588255706689)(生命周期.png)]

生命周期详述
1) 组件的三个生命周期状态:

Mount:插入真实 DOM

Update:被重新渲染

Unmount:被移出真实 DOM

2)React 为每个状态都提供了勾子(hook)函数

componentWillMount()

componentDidMount()

componentWillUpdate()

componentDidUpdate()

componentWillUnmount()

3)生命周期流程

a.第一次初始化渲染显示: ReactDOM.render() 1次

constructor(): 创建对象初始化state

componentWillMount() : 将要插入回调

render() : 用于插入虚拟DOM回调

componentDidMount() : 已经插入回调

b.每次更新state: this.setSate() n次

componentWillUpdate() : 将要更新回调

render() : 更新(重新渲染)

componentDidUpdate() : 已经更新回调

c.移除组件: ReactDOM.unmountComponentAtNode(containerDom) 1次

componentWillUnmount() : 组件将要被移除回调

重要的勾子
  1. render(): 初始化渲染或更新渲染调用

  2. componentDidMount(): 开启监听, 发送ajax请求

  3. componentWillUnmount(): 做一些收尾工作, 如: 清理定时器

  4. componentWillReceiveProps(): 后面需要时讲

编码操作
需求: 自定义组件
  1. 让指定的文本做显示/隐藏的渐变动画
  2. 切换持续时间为2S
  3. 点击按钮从界面中移除组件界面
<script type="text/babel">
  /*
  需求: 自定义组件
    1. 让指定的文本做显示/隐藏的动画
    2. 切换时间为2S
    3. 点击按钮从界面中移除组件界面
   */
  class Fade extends React.Component {

    constructor (props) {
      super(props)
      console.log('constructor(): 创建组件对象')
      this.state = {
        opacity: 1
      }
      this.removeComponent = this.removeComponent.bind(this)
    }

    componentWillMount () {
      console.log('componentWillMount(): 初始化将要挂载')
    }

    componentDidMount () {// 在此方法中启动定时器/绑定监听/发送ajax请求
      console.log('componentDidMount(): 初始化已经挂载')
      // 保存到当前组件对象中
      this.intervalId = setInterval(function () {
        console.log('--------')
        // 得到当前opacity
        let {opacity} = this.state
        // 更新opacity
        opacity -= 0.1
        if(opacity<=0) {
          opacity = 1
        }
        // 更新状态
        this.setState({opacity})
      }.bind(this), 200)
    }

    componentWillUpdate () {
      console.log('componentWillUpdate(): 将要更新')
    }
    componentDidUpdate () {
      console.log('componentDidUpdate(): 已经更新')
    }

    componentWillUnmount () {// 清除定时器/解除监听
      console.log('componentWillUnmount(): 将要被移除')
      clearInterval(this.intervalId)
    }

    removeComponent () {
      ReactDOM.unmountComponentAtNode(document.getElementById('example'))
    }

    render() {
      console.log('render() 渲染组件')
      return (
        <div>
          <h2 style={{opacity:this.state.opacity}}>{this.props.content}</h2>
          <button onClick={this.removeComponent}>不活了</button>
        </div>
      )
    }
  }
  ReactDOM.render(<Fade content="react学不会, 怎么办?"/>, document.getElementById('example'))
</script>

6.虚拟DOM与DOM Diff算法

检测哪些需要更新哪些不需要更新,提高效率

基本原理图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vuhkQNYt-1588255706695)(虚拟DOM与Diff算法.png)]

编码操作
<script type="text/babel">
  /*
  验证:
  虚拟DOM+DOM Diff算法: 最小化页面重绘
  */

  class HelloWorld extends React.Component {
    constructor(props) {
      super(props)
      this.state = {
          date: new Date()
      }
    }

    componentDidMount () {
      setInterval(() => {
        this.setState({
            date: new Date()
        })
      }, 1000)
    }

    render () {
      console.log('render()')
      return (
        <p>
          Hello, <input type="text" placeholder="Your name here"/>!&nbsp;
          <span>It is {this.state.date.toTimeString()}</span>
        </p>
      )
    }
  }

  ReactDOM.render(
    <HelloWorld/>,
    document.getElementById('example')
  )
</script>

React应用

1. React脚手架

理解
  1. xxx脚手架: 用来帮助程序员快速创建一个基于xxx库的模板项目
  • 包含了所有需要的配置
  • 指定好了所有的依赖
  • 可以直接安装/编译/运行一个简单效果
  1. react提供了一个用于创建react项目的脚手架库: create-react-app

  2. 项目的整体技术架构为: react + webpack + es6 + eslint

  3. 使用脚手架开发的项目的特点: 模块化, 组件化, 工程化

创建并进入

npm install -g create-react-app

create-react-app hello-react

cd hello-react

npm start

npm root -g 查看全局下载的根目录

PS:在文件夹地址栏直接cmd可以直接打开此目录的cmd

react脚手架项目结构
  • 在文件package.json中

    • "dependencies"是开发(编译打包)依赖的环境配置
    • “devDependencies"是运行时依赖的环境配置
  • ReactNews

    |–node_modules—第三方依赖模块文件夹

    |–public

    ​ |–index.html-----------------主页面

    |–scripts

    |– build.js-------------------build**打包引用配置

    |– start.js-------------------start**运行引用配置

    |–src------------源码文件夹

    |–components-----------------react**组件

    ​ |–index.js-------------------应用入口js

    |–.gitignore------git版本管制忽略的配置

    |–package.json----应用包配置文件:

    ​ 1.标识:1)name version

    ​ 2.依赖:运行依赖和开发依赖

    ​ 3.运行/打包: scripts 通过npm run运行

    |–README.md-------应用描述说明的readme文件

  • 组件后缀名可以是.js/.jsx,一般是.jsx

  • 组件文件名小写,组件名首字母大写

  • 所有的组件类都要引入:

2. demo1 实现一个评论管理功能

点我

练习源代码

视频源代码

注意,原src文件可能已经改为src-对应的demo名,需要运行时要改回来

React ajax

1. 理解

1.1 前置说明
  1. React本身只关注于界面, 并不包含发送ajax请求的代码

  2. 前端应用需要通过ajax请求与后台进行交互(json数据)

  3. react应用中需要集成第三方ajax库(或自己封装)

1.2 常用的ajax请求库
  1. jQuery: 比较重, 如果需要另外引入不建议使用

  2. axios: 轻量级, 建议使用

​ a. 封装XmlHttpRequest对象的ajax

​ b. promise风格

​ c. 可以用在浏览器端和node服务器端

  1. fetch: 原生函数, 但老版本浏览器不支持

​ a. 不再使用XmlHttpRequest对象提交ajax请求

​ b. 为了兼容低版本的浏览器, 可以引入兼容库fetch.js

1.3 要求实现效果

要先引入axios库

需求:

  1. 界面效果如下
  2. 根据指定的关键字在github上搜索匹配的最受关注的库
  3. 显示库名, 点击链接查看库
  4. 测试接口: https://api.github.com/search/repositories?q=r&sort=stars

2. axios

2.1 文档

https://github.com/axios/axios

2.2 相关API
2.2.1 get请求
axios.get('/user?ID=12345')
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

axios.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

2.2.2 post请求
axios.post('/user', {
 firstName: 'Fred',
    lastName: 'Flintstone'
})
.then(function (response) {
  console.log(response);
})
.catch(function (error) {
  console.log(error);
});

2.3 axios实现
需求:
  1. 界面效果如下
  2. 根据指定的关键字在github上搜索匹配的最受关注的库
  3. 显示库名, 点击链接查看库
  4. 测试接口: https://api.github.com/search/repositories?q=r&sort=stars
<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/axios/0.17.1/axios.min.js"></script>
<script type="text/babel">
  /*
  需求:
    1. 界面效果如下
    2. 根据指定的关键字在github上搜索匹配的最受关注的库
    3. 显示库名, 点击链接查看库
    4. 测试接口: https://api.github.com/search/repositories?q=r&sort=stars
  */

  class MostStarRepo extends React.Component {

    state = {
      repoName: '',
      repoUrl: ""
    }

    componentDidMount() {
      const url = `https://api.github.com/search/repositories?q=r&sort=stars`

      //使用axios发送异步请求
            axios.get(url)
                .then(response=>{
                 const result = response.data
                  //console.log(result)
                  //console.log(response)
                  //得到数据
                  const{name,html_url} = result.items[0]
                  //更新状态
                  this.setState({repoName:name,repoUrl:html_url})
                  .catch((error)=>{
                    alert(error.message)
                  })
                })
    }

    render() {
      const {repoName, repoUrl} = this.state
      if (!repoName){
        return <h2>Loading......</h2>
      }else{
        return <h2>Most star repo is <a href={repoUrl}>{repoName}</a></h2>
      }
    }
  }

  ReactDOM.render(<MostStarRepo searchWord="r"/>, document.getElementById('example'))
</script>

3. Fetch

3.1 文档
  1. https://github.github.io/fetch/

  2. https://segmentfault.com/a/1190000003810652

3.2 相关API
3.2.1 get请求
fetch(url).then(function(response) {
  return response.json()
}).then(function(data) {
  console.log(data)
}).catch(function(e) {
  console.log(e)
});

3.2.2 post请求
fetch(url, {
  method: "POST",
  body: JSON.stringify(data),
}).then(function(data) {
  console.log(data)
}).catch(function(e) {
  console.log(e)
})
3.3 Fetch实现
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>11_ajax</title>
</head>
<body>
<div id="example"></div>

<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/axios/0.17.1/axios.min.js"></script>
<script type="text/babel">
  /*
  需求:
    1. 界面效果如下
    2. 根据指定的关键字在github上搜索匹配的最受关注的库
    3. 显示库名, 点击链接查看库
    4. 测试接口: https://api.github.com/search/repositories?q=r&sort=stars
  */

  class MostStarRepo extends React.Component {

    state = {
      repoName: '',
      repoUrl: ""
    }

    componentDidMount() {
      const url = `https://api.github.com/search/repositories?q=r&sort=stars`
      //使用Fetch发送异步请求
     fetch(url)
        .then(response => {
          return response.json()
        })
        .then(data => {
          //得到数据
          const {name, html_url} = data.items[0]
          //更新状态
          this.setState({repoName: name, repoUrl: html_url})
        })
    }

    render() {
      const {repoName, repoUrl} = this.state
      if (!repoName) {
        return <h2>Loading......</h2>
      } else {
        return <h2>Most star repo is <a href={repoUrl}>{repoName}</a></h2>
      }
    }
  }

  ReactDOM.render(<MostStarRepo searchWord="r"/>, document.getElementById('example'))
</script>
</body>
</html>

4.demo2 实现github用户搜索功能

点我

自己实现的

别人实现的

记得下载包axios npm install --save axios

重要技术总结

1. 组件间通信

1.1 方式一: 通过props传递
  1. 共同的数据放在父组件上, 特有的数据放在自己组件内部(state)

  2. 通过props可以传递一般数据和函数数据, 只能一层一层传递

  3. 一般数据–>父组件传递数据给子组件–>子组件读取数据

  4. 函数数据–>子组件传递数据给父组件–>子组件调用函数

1.2 方式二: 使用消息订阅(subscribe)-发布(publish)机制
  1. 工具库: PubSubJS

  2. 下载: npm install pubsub-js --save

  3. 使用:

​ import PubSub from ‘pubsub-js’ //引入

​ PubSub.subscribe(‘delete’, function(data){ }); //订阅

​ PubSub.publish(‘delete’, data) //发布消息

实例 根据demo2改编

兄弟组件 爷孙组件之间通信 用这种方式比较好,不用再通过父组件传递

app.jsx 里面没有state等内容,因为孩子传递数据跟他没关系了

import React from 'react'
import Search from './search'
import Main from './main'

export default class App extends React.Component {

  render() {
    return (
      <div id="app">
      <div className="container">
        <Search />
        <Main />
      </div>
      </div>
    )
  }

}

search.jsx

1.3 方式三: redux

2. 事件监听理解

2.1原生DOM事件
  1. 绑定事件监听

​ a. 事件名(类型): 只有有限的几个, 不能随便写

​ b. 回调函数

  1.    触发事件
    

​ a. 用户操作界面

​ b. 事件名(类型)

​ c. 数据()

2.2 自定义事件(消息机制)
  1. 绑定事件监听

​ a. 事件名(类型): 任意

​ b. 回调函数: 通过形参接收数据, 在函数体处理事件

  1. 触发事件(编码)

​ a. 事件名(类型): 与绑定的事件监听的事件名一致

​ b. 数据: 会自动传递给回调函数

3. ES6常用新语法

  1. 定义常量/变量: const/let

  2. 解构赋值: let {a, b} = this.props import {aa} from ‘xxx’

  3. 对象的简洁表达: {a, b}

  4. 箭头函数:

​ a.常用场景

​ 组件的自定义方法: xxx = () => {}

​ 参数匿名函数

​ b.优点:

​ 简洁

​ 没有自己的this,使用引用this查找的是外部this

  1. 扩展(三点)运算符: 拆解对象(const MyProps = {}, <Xxx {…MyProps}>)

  2. 类: class/extends/constructor/super

  3. 工具库: PubSubJS

  4. 下载: npm install pubsub-js --save

  5. 使用:

​ import PubSub from ‘pubsub-js’ //引入

​ PubSub.subscribe(‘delete’, function(data){ }); //订阅

​ PubSub.publish(‘delete’, data) //发布消息

实例 根据demo2改编

兄弟组件 爷孙组件之间通信 用这种方式比较好,不用再通过父组件传递

app.jsx 里面没有state等内容,因为孩子传递数据跟他没关系了

import React from 'react'
import Search from './search'
import Main from './main'

export default class App extends React.Component {

  render() {
    return (
      <div id="app">
      <div className="container">
        <Search />
        <Main />
      </div>
      </div>
    )
  }

}

search.jsx

1.3 方式三: redux

2. 事件监听理解

2.1原生DOM事件
  1. 绑定事件监听

​ a. 事件名(类型): 只有有限的几个, 不能随便写

​ b. 回调函数

  1.    触发事件
    

​ a. 用户操作界面

​ b. 事件名(类型)

​ c. 数据()

2.2 自定义事件(消息机制)
  1. 绑定事件监听

​ a. 事件名(类型): 任意

​ b. 回调函数: 通过形参接收数据, 在函数体处理事件

  1. 触发事件(编码)

​ a. 事件名(类型): 与绑定的事件监听的事件名一致

​ b. 数据: 会自动传递给回调函数

3. ES6常用新语法

  1. 定义常量/变量: const/let

  2. 解构赋值: let {a, b} = this.props import {aa} from ‘xxx’

  3. 对象的简洁表达: {a, b}

  4. 箭头函数:

​ a.常用场景

​ 组件的自定义方法: xxx = () => {}

​ 参数匿名函数

​ b.优点:

​ 简洁

​ 没有自己的this,使用引用this查找的是外部this

  1. 扩展(三点)运算符: 拆解对象(const MyProps = {}, <Xxx {…MyProps}>)

  2. 类: class/extends/constructor/super

  3. ES6模块化: export default | import