React基础二

目录

  • react相关说明
    • react不能像Vue一样直接在浏览器运行
    • React的快速构建工具
    • 通过CRA来构建项目
      • 构建流程
      • 常见问题
  • react元素与组件
    • React元素
    • 函数式组件
    • 类组件
    • 辅助工具
  • 组件的传参和接参
  • 组件的组合和嵌套
    • 组件的组合
    • 组件的嵌套
    • 在子组件中显示父组件中子组件书写的内容
  • jsx原理【 了解 】
  • 组件中的DOM样式
  • React的数据定义问题
    • 属性
    • 状态
  • 属性props验证
  • jsx里面的注释
  • 属性vs状态
    • 相同点
    • 不同点
    • state
    • props
    • 使用场景
    • 总结
  • 状态提升
  • 状态组件

说明

React中使用的是 es6 模块化规范 (即import引入,exports default导出)

  1. React是不能直接在浏览器中运行的,我们必须借助工具才能运行React程序
    • 因为React是jsx,它必须经过webpack编译为js才能运行
  2. React的快速构建工具
    • 脚手架作用:快速构建一个项目
    • 类型
      • CRA [ 大纲要求 - react官方推荐的 ]
      • Dva
      • Umi
  3. 通过CRA来构建项目
  • 构建流程
    • 安装CRA [ create-react-app ]
      • 全局安装
        • yarn add create-react-app global
        • cnpm i create-react-app -g
      • 临时使用 [ npx ]
        • npx create-react-app 项目名称
    • 安装需要等待一段时间,这个过程实际上会安装三个东西
      • react: react的顶级库
      • react-dom: 因为react有很多的运行环境,比如app端的react-native, 我们要在web上运行就使用react-dom
      • react-scripts: 包含运行和打包react应用程序的所有脚本及配置
      • 出现下面的界面,表示创建项目成功:
      Success! Created your-app at /dir/your-app
      Inside that directory, you can run several commands:
      
        npm start      //  开发环境下运行
          Starts the development server.
      
        npm run build  // 生产环境打包
          Bundles the app into static files for production.
      
        npm test       // 测试环境下运行
          Starts the test runner.
      
        npm run eject  // 配置文件抽离,这个操作是不可逆的【 抽离的就不能返回 】
        	// webpack配置放在了node_modules/react-scripts里面
          Removes this tool and copies build dependencies, configuration files
          and scripts into the app directory. If you do this, you can’t go back!
      
      We suggest that you begin by typing:
      
        cd your-app
        npm start
      
      Happy hacking!
      
    • 启动项目
      • $ yarn start
      • 启动项目出错可能原因
      • 可能配置文件抽离少了,手动安装没有抽离出来的配置
    • 打包项目
      • $ yarn build
    • 配置文件抽离
      • $ yarn eject 这个动作不可逆【 不能返回 】
    • 启动项目后,会生成项目的目录结构如下:
    ├── README.md							使用方法的文档
    ├── node_modules					所有的依赖安装的目录
    ├── yarn-lock.json			锁定安装时的包的版本号,保证团队的依赖能保证一致。
    ├── package.json					 项目依赖配置记录文件 、 记录项目脚本命令
    ├── public								   静态公共目录( 生产环境 ) 不会被webpack编译
    |-- config                   项目webpack配置文件
    |-- scripts                  项目wepback脚本命令执行文件
    └── src									开发用的源代码目录
    	- index.js 项目入口文件
    	- index.css 项目全局样式
    	- App.js 构建了一个App组件,是项目最大的组件 【 类似根组件 】
    	- App.css 是App组件的样式文件
    	- App.test.js 是App组件测试文件 
    	- logo.svg 初始项目的界面logo
    	- serverWorker 内部文件,我们不操作 
    
    • 常见问题:
    • npm安装失败
      • 切换为npm镜像为淘宝镜像
      • 使用yarn,如果本来使用yarn还要失败,还得把yarn的源切换到国内
        yarn config set registry https://registry.npm.taobao.org // 配置yarn镜像源
        
        yarn config list // 查看yarn 镜像列表
        
      • 如果还没有办法解决,请删除node_modules及yarn-lock.json然后重新执行cnpm install命令
      • 再不能解决就删除node_modules及yarn-lock.json的同时清除npm缓存npm cache clean --force之后再执行npm install命令
      • 环境变量问题
      • react-scripts 版本过高问题 ( 降低版本 react-script@2.1.8)
    • 以上全不行,咋整?
      • 将旁边可以安装的人的目录文件拷贝过来,注意不要拷贝node_modules
        • 拷贝过来之后,记得cnpm i

react元素与组件

  1. React元素
    • 概念
    • React元素就是一个普通的jsx(虚拟DOM对象模型)
    • 实现代码
     /* 
         * 项目入口文件 - 整个项目的灵魂
     */
     import React from 'react'//React的顶级库,它里面有很多的React的api,并且我们要想使用jsx,那么必须引入它,它是对jsx的支持
     import ReactDOM from 'react-dom'//它的作用就是将React组件编译为DOM结构,然后插入到浏览器网页中
     
     // ReactDOM.render( 元素/组件, 一个已有的容器 )
     //此代码的作用:用ReactDOM里面的render方法将React组件解析为DOM结构,然后再插入到root结构里面
     ReactDOM.render(
         <h3> React元素 </h3>,//在js中书写html,react元素
         document.querySelector('#root')//获取已有容器
     )
    
  2. 函数式组件
    • 概念:就是定义一个函数,将函数以标签化的形式使用
    • 函数式组件的推导过程
    • 将要用的html结构定义成一个变量
      import React from 'react'
      import ReactDOM from 'react-dom'
      
      const ele = <h3> 函数式组件 </h3>
      
      ReactDOM.render(
        ele,
        document.querySelector('#root')
      )
      
    • 由于元素没有办法传递参数,所以我们就需要把之前定义的变量改为一个方法,让这个方法去return一个元素:
    import React from 'react'
    import ReactDOM from 'react-dom'
    
    // 特别注意这里的写法,如果要在JSX里写js表达式(只能是表达式,不能流程控制),就需要加 {},包括注释也是一样,并且可以多层嵌套
    const app = (props) => <h1>欢迎进入{props.name}的世界</h1>
    
    ReactDOM.render(
      app({
        name: 'react'
      }),
      document.getElementById('root')
    )
    
    • 这里我们定义的方法实际上也是react定义组件的第一种方式-定义函数式组件,这也是无状态组件。但是这种写法不符合react的jsx的风格,更好的方式是使用以下方式进行改造
    • 函数式组件(组件名称必须大写,否则会报错)
    import React from 'react'
    import ReactDOM from 'react-dom'
    
    const App = ( props ) => {//这样,我们的内容就可以灵活多遍了
      //props参数会接受App组件身上的属性
      return <h3> { props.info } </h3>//React模板语法{}
    }
    
    ReactDOM.render(
      // App({
      //   info:'传参'
      // }),
      <App info = '标签化形式'/>,//改成标签化形式,更符合组件的思维
      document.querySelector('#root')
    )
    
    • React模板语法
      • 单括号{}
    • 在React中,函数也可以是一个组件,但是记住了,这个函数必须返回一个jsx结构
    • 函数式组件由一个属性props接收, 这个props可以接收绑定在函数式组件身上的属性
    • 好处:
      • js的最大特点: 函数式编程
      • react符合函数式编程思想的
      • 函数的好处: 复用性高、独立作用域
  3. React第二类组件: 类组件
    • 实现代码
    //index.js文件
    import React from 'react'
    import ReactDOM from 'react-dom'
    import App from './App'
    ReactDOM.render(
      //传参
      <App info = '这是类组件参数'/>,
      document.querySelector('#root')
    )
    
    
    //引入React、父组件Component、唯一根元素Fragment
    import React,{ Component,Fragment } from 'react'
    
    //创建类组件
    class App extends Component{
        render () {
            //jsx结构 一定要有唯一根元素
            return (
                //Fragment唯一根元素,在解析时不会有任何展示,不会渲染
                <Fragment>
                    <h3> 类组件 </h3>
                    //通过this.props.info来接收绑定在App组件身上的参数
                    <h3> info:{ this.props.info } </h3>
                </Fragment>
            )
        }
    }
    //导出类组件
    export default App
    
    • 其中render是一个函数,return后面跟括号
    • es6 class组件其实就是一个构造器,每次使用组件都相当于在实例化组件
    import React from 'react'
    import ReactDOM from 'react-dom'
    
    class App extends React.Component {
      render () {
        return (
      		<h1>欢迎进入{this.props.name}的世界</h1>
      	)
      }
    }
    
    const app = new App({
      name: 'react'
    }).render()
    
    ReactDOM.render(
      app,
      document.getElementById('root')
    )
    
  4. 辅助工具
    • vs code 插件
      • Simple React Snippets
      • ES7 React/Redux/GraphQL/React-Native snippets
      • React-Native/React/Redux snippets for es6/es7
    • chrome浏览器
      • React developer tools

创建类组件更老的一种方法

  • 在16以前的版本还支持这样创建组件, 但现在的项目基本上不用
  • 实现代码
// react  15.x
React.createClass({
  render () {
    return (
      <div>{this.props.xxx}</div>
  	)
  }
})

组件的传参和接参

  • 类组件
    • 传参
    <App info = '这是类组件参数'/>
    
    • 接参
     <h3> info:{ this.props.info } </h3>
    
  • 函数式组件
    • 传参
    <FnComp name = '张三'></FnComp>
    
    • 接参
    //通过props.name来接收
    import React,{ Component } from 'react'
    const FnComp = props => {
        // console.log( this ) undefined  
        return (
            <Fragment>
                //使用props.name来接收,函数式组件中没有this
                <h3> { props.name } </h3>
            </Fragment>
        )
    }
    export default FnComp
    

    注意:函数式组件里面的this是undefined,而类组件里面的this就是当前组件App

组件的组合和嵌套

  • 组件的组合
    • 概念
      • 将一个组件写在另一个组件的内容中,然后在外层组件中通过 this.props.children来接收内容中的组件,包括里面的内容
    • 代码实现
    //1.App组件
    import React,{ Component,Fragment } from 'react'
    import Father from './components/Father'
    import Girl from './components/Girl'
    class App extends Component {
        render () {
            return (
                <Fragment>
                    <h3> info:{ this.props.info } </h3>
                    //组件的组合
                    <Father>
                        <Girl></Girl>
                    </Father>
                </Fragment>
            )
        }
    }
    export default App
    //2.Father组件
    import React,{ Component,Fragment } from 'react'
    class Father extends Component{
        render () {
            return (
                <Fragment>
                    { this.props.children }
                </Fragment>
            )
        }
    }
    export default Father
    //3.Girl组件
    import React,{ Component,Fragment } from 'react'
    const Girl = props => {
        return (
            <Fragment>
                Gril
            </Fragment>
        )
    }
    export default Girl
    
  • 组件的嵌套【 更推荐 】
    • 概念
      • 将子组件在父组件的jsx中以标签的形式使用
    • 实现代码
    //1.父组件
    import React,{ Component,Fragment } from 'react'
    import Son from './Son'
    class Father extends Component{
        render () {
            return (
                <Fragment>
                    <h3> 这是父组件 </h3>
                    <h3> 引入子组件 </h3>
                    <Son name = '张三'>
                        {/* 在子组件中书写{ this.props.children }来显示这里的内容 */}
                        <p> 显示子组件的内容 </p>
                    </Son>
                </Fragment>
            )
        }
    }
    export default Father
    
    //2.子组件
    import React,{ Component,Fragment } from 'react'
    class Son extends Component{
        render () {
            return (
                <Fragment>
                    <h3> 子组件 </h3>
                    //接收在父组件中子组件身上绑定的属性
                    <p> { this.props.name } </p>
                </Fragment>
            )
        }
    }
    export default Son
    //3.父组件中引入Father组件
    
  • 在子组件中显示父组件中子组件书写的内容
//1.父组件中子组件中书写内容
 <Son name = '张三'>
    {/* 在子组件中书写{ this.props.children }来显示这里的内容 */}
    <p> 显示子组件的内容 </p>
 </Son>
 
 //2.显示在父组件中书写的子组件内容
 { this.props.children }

jsx原理

  • 概念:javascript语法扩展(js+xml)
  • React中通过React.createElement()将jsx编译为js对象模型
  • jsx解决的问题
    • 方便我们在js中写html结构
  • 编译的过程把类似 HTML 的 JSX 结构转换成 JavaScript 的对象结构
    • 源代码
    import React from 'react'
    import ReactDOM from 'react-dom'
    
    class App extends React.Component {
      render () {
        return (
          <div className='app' id='appRoot'>
            <h1 className='title'>欢迎进入React的世界</h1>
            <p>
              React.js 是一个构建页面 UI 的库
            </p>
          </div>
        )
      }
    }
    
    ReactDOM.render(
    	<App />,
      document.getElementById('root')
    )
    
    • 编译后
    import React from 'react'
    import ReactDOM from 'react-dom'
    
    class App extends React.Component {
      render () {
        return (
            React.createElement(
            "div",
            {
              className: 'app',
              id: 'appRoot'
            },
            React.createElement(
              "h1",
              { className: 'title' },
              "欢迎进入React的世界"
            ),
            React.createElement(
              "p",
              null,
              "React.js 是一个构建页面 UI 的库"
            )
          )
        )
      }
    }
    
    ReactDOM.render(
    	React.createElement(App),
      document.getElementById('root')
    )
    
    • React.createElement 会构建一个 JavaScript 对象来描述你 HTML 结构的信息,包括标签名、属性、还有子元素等, 语法为
    React.createElement(
      type,
      [props],
      [...children]
    )
    

    JSX — 使用react构造组件,babel进行编译—> 将JavaScript对象 — 通过ReactDOM.render()—>渲染成DOM元素 —>插入页面

组件中的DOM样式

  • 分类(四种)
    • 行内样式
    • 使用class
    • 不同条件添加不同样式
    • css-in-js
  • 行内样式
    • 实现方式
      • 想给虚拟dom添加行内样式,需要使用表达式传入样式对象的方式来实现:
        • 定义样式对象的三种方式
          • 直接在标签内定义
          • 在return外面定义
          • 在render外面定义(实例属性)
          //这里第一个{}代表语法模板;第二个{}代表一个对象
          import React,{ Component,Fragment } from 'react'
          
          class StyleOne extends Component {
              styleDemo3 = {//实例属性
                  text:{ width:'100px',height:'100px',background:'blue' }
              };
              render () {
                  const styleDemo2 = {
                      text:{ width:'100px',height:'100px',background:'red' }
                  };
                  return (
                      <Fragment>
                          <h3> 行内样式 </h3>
                          {/* 方式一:直接在标签内定义样式对象 */}
                          <p style = {{ width:'100px',height:'100px',background:'green' }} > 行内样式 </p>
                          {/* 方式二:在return外面定义样式对象 */}
                          <p style = { styleDemo2.text }></p>
                          {/* 方式三:在render外面定义样式对象 */}
                          <p style = { this.styleDemo3.text }></p>
                      </Fragment>
                  )
              }
          }
          
          export default StyleOne
          
  • 加类名
    • 实现方式
    import React,{ Component,Fragment } from 'react'
    //模块化引入样式文件
    import './Style_demo2_css.css'
    
    class StyleTwo extends Component{
        render () {
            return (
                <Fragment>
                    <h3> 样式添加---类名 </h3>
                    <p className = "size bg"> 类名添加样式 </p>
                </Fragment>
            )
        }
    }
    
    export default StyleTwo
    

    注意:这里要使用className来添加类名,不能使用class添加类名,因为class是关键字

  • React中使用sass
    • 要安装两个包
    yarn add node-sass
    yarn add sass-loader
    
    • scss样式文件
    $color: pink;
    
    .size{
      width: 100px;
      height: 100px;
    
    }
    .bg{
      background: $color;
    }
    
    • 模块化引入
    import './CompTwo.scss'
    
  • React中使用less
  • 不同条件添加不同样式
    • 安装(要是安装失败就换一个方式安装)
    yarn add classname/classnames
    
    • 在npmjs中找classname的用法
    classname({
        one: true,
        two: false,
        three: true
    })
    
    • 实现代码
    //引入classname
    import classname from 'classname'
    
    //classname是一个函数,里面参数是一个对象,通过开关来控制类名是否添加
     <Fragment>
        <h3> React样式添加 - 不同的条件添加不同的样式 </h3>
        <p className = {classname({
          size: true,
          success: false,
          danger: true
        })}></p>
     </Fragment>
    
  • 样式组件
    • 安装
    cnpm i styled-components -D
    
    • styled-components是针对React写的一套css-in-js框架,简单来讲就是在js中写css
    • 实现代码
    //引入style-components
    import styled from 'styled-components'
    
    /*在Container中写样式
    const Container = styled.标签名`
        这里面写样式
    `*/
    
    const Container = styled.div`
      width: 200px;
      height: 200px;
      border: 1px dashed black;
      header{
        width: 50px;
        height: 50px;
        background: ${ props => props.flag && 'purple' || 'red' };
        i{
          display: block;
          width: 25px;
          height: 25px;
          <!--在组件Container组件身上绑定一个样式属性时,可以在styled.div中用过props来接收属性-->
          background: ${ props => props.color };
        }
      }
    `
    
      <Fragment>
        <h3> React样式添加 - 样式组件 </h3>
        <Container color = "green" flag = { false }>
          <header> 头部 <i></i></header>
        </Container>
      </Fragment>
    

React的数据定义形式

  • React中属性的定义
    • 属性的概念:属性是描述性质、特点的,属性不能被组件自己更改,但是你可以通过父组件主动重新渲染的方式来传入新的 props
    • 外部传入
      • 实现:在组件的标签化形式中绑定一个属性,然后在组件中通过this.props.属性名【或者peops.属性名】接收
      • 代码实现
      //1.PropsDemo组件
      import React,{ Component,Fragment } from 'react'
      
      class PropsDemo extends Component{
          render () {
              return (
                  <Fragment>
                      <h3> 属性的定义---外部引入 </h3>
                      {/* 接收绑定在PropsDemo组件身上的属性 */}
                      <p> { this.props.name } </p>
                  </Fragment>
              )
          }
      }
      
      export default PropsDemo
      
      //App组件
      import React,{ Component,Fragment } from 'react'
      import PropsDemo from './components/PropsDemo'
      
      class App extends Component {
          render () {
              const name = '外部引入'
              return (
                  <Fragment>
                      <PropsDemo name = { name }></PropsDemo>
                  </Fragment>
              )
          }
      }
      
      export default App
      
    • 内部定义
      • 实现:通过static关键字结合defaultProps来定义,在组件中依然通过{ this.props.属性名 }接收
      • 代码实现
      import React,{ Component,Fragment } from 'react'
      
      class PropsDemo extends Component{
          //内部定义--通过static关键字
          static defaultProps = {
              age:100
          }
          render () {
              return (
                  <Fragment>
                      <h3> 属性定义---内部定义 </h3>
                      <p> { this.props.age } </p>
                  </Fragment>
              )
          }
      }
      
      export default PropsDemo
      

注意:React中的属性是不可变的,内部设置的属性是不去更改它的

  • React中状态的定义
    • 概念:
      • 状态就是组件描述某种显示情况的数据,由组件自己设置和更改,也就是说由组件自己维护。
    • 使用目的
      • 为了在不同的状态下使组件的显示不同(自己管理)
    • 定义方式
      • 实例属性形式:利用state直接定义,然后利用{ this.state.info }接收
      import React,{ Component,Fragment } from 'react'
      
      class StateDemo extends Component {
          //利用state直接定义
          state = {
              info:'状态定义---直接定义'
          }
          render () {
              return (
                  <Fragment>
                      <h3> 状态定义---直接利用stata定义 </h3>
                      //通过{ this.state.info }接收
                      <p> { this.state.info } </p>
                  </Fragment>
              )
          }
      }
      
      export default StateDemo
      
      • 在构造函数里面定义,然后利用{ this.state.info }接收【 推荐 】
      class StateDemo extends Component {
          //定义方式二:在构造函数里面定义
          constructor () {
              super()
              this.state = {
                  info:'状态定义---在构造函数里面定义'
              }
          }
          render () {
              return (
                  <Fragment>
                      <h3> 状态定义---直接利用stata定义 </h3>
                      <p> { this.state.info } </p>
                  </Fragment>
                  )
              }
          }
      
      export default StateDemo
      

注意:组件自己的状态更改

属性props验证

  • 作用:让写组件的人可以给组件的props设定参数检查
  • 安装检测工具
cnpm i prop-types -S
  • 实现代码
import propsTypes from 'prop-types'

    <Fragment>
        <h3> 属性验证 </h3>
        {/* 外部引入price属性 */}
        <p> { this.props.price + 1000 } </p>
    </Fragment>

    // 属性验证
    /*
        import propsTypes from 'prop-types'
        类.propTypes = {
            属性:引入的prop-types.限定类型
        }
    */
    
    PropsCheck.propTypes = {
        //规定传入的属性的属性值只能是数字类型,其他类型会报错
        price:propsTypes.number
    }
    
    //报错的信息
    index.js:1375 Warning: Failed prop type: Invalid prop `price` of type `string` supplied to `PropsCheck`, expected `number`.
    in PropsCheck (at App.js:11)
    in App (at src/index.js:8)

jsx里面的注释

{/* jsx里面的注释 */}

属性vs状态

  • 相似点:都是纯js对象,都会触发render更新,都具有确定性(状态/属性相同,结果相同)

外部传入属性,内部修改状态,都会触发render更新

  • 不同点
    1. 属性能从父组件获取,状态不能
    2. 属性可以由父组件修改,状态不能,组件自己的状态自己更改
    3. 属性能在内部设置默认值,状态也可以
    4. 属性不在组件内部修改,状态要改 【 外部传入的属性只能外部修改,内部定义的属性不允许修改】
    5. 属性能设置子组件初始值,状态不可以【设置子组件初始值:通过static defaultProps】
    6. 属性可以修改子组件的值,状态不可以
  • state
    • 作用
      • state 的主要作用是用于组件保存、控制、修改自己的可变状态
    • 状态的修改
      • state 在组件内部初始化,可以被组件自身修改,而外部不能访问也不能修改。你可以认为 state 是一个局部的、只能被组件自身控制的数据源。state 中状态可以通过 this.setState方法进行更新,setState 会导致组件的重新渲染。
  • props
    • 作用
      • **props 的主要作用是让使用该组件的父组件可以传入参数来配置该组件**
    • 修改
      • 它是外部传进来的配置参数,组件内部无法控制也无法修改。除非外部组件主动传入新的 props,否则组件的 props 永远保持不变。
  • 使用场景
    • 规则:尽量少地用 state,多用 props。【数据最好是由外传入内】

总结:组件props要想变,那么就外部修改;组件state要想变,那么组件内部自身通过setState修改

状态提升

  • 如果有多个组件共享一个数据,把这个数据放到共同的父级组件中来管理

状态组件

  • 无状态组件
    • 概念:没有state组件
    • 举例:函数式组件
  • 有状态组件
    • 概念:有state组件
    • 举例:类组件
  • 使用场景
    • 功能复杂,我们使用类组件
    • 功能单一,我们使用函数式组件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值