React 学习笔记(1) 基础语法

参看:视频地址

1. ReactDOM.render()

import ReactDOM from 'react-dom'

/**
 * ReactDOM.render() 将模板转化为 HTML 语言 render
 * 参数1: 要渲染的模板
 * 参数2: 挂载到的dom元素
 */
ReactDOM.render(
  

Hello, world!

, document.getElementById('example') );

2. React.createElement()

import React from 'react'
import ReactDOM from 'react-dom'

/**
 * React.createElement()
 * 参数1: 标签名
 * 参数2: 标签属性
 * 参数3: 标签内容
 * 参数4: 其他节点
 */
// 需要 babel loader 解析jsx语法
const myH1 = 
哈哈哈
const myDiv = React.createElement('div', { title: 'this is a div', id: 'mydiv' }, '这是一个div', myH1) // 将 myH1 放在 myDiv中,渲染到 #app 标签中 ReactDOM.render(myDiv, document.getElementById('app'))

3. jsx 语法

3.1 jsx语法的配置

jsx语法不能直接使用,需要@babel/preset-react翻译。

// package.json
"devDependencies": {
    "@babel/core": "^7.6.2",
    "@babel/plugin-proposal-class-properties": "^7.5.5",
    "@babel/plugin-transform-runtime": "^7.6.2",
    "@babel/preset-env": "^7.6.2",
    "@babel/preset-react": "^7.0.0",
    "@babel/runtime": "^7.6.2",
    "babel-loader": "^8.0.6",
    "html-webpack-plugin": "^3.2.0",
    "webpack": "^4.41.2",
    "webpack-cli": "^3.3.9",
    "webpack-dev-server": "^3.8.2"
},
"dependencies": {
    "react": "^16.10.2",
    "react-dom": "^16.10.2"
}

 

// .babelrc
{
  "presets": ["@babel/preset-env", "@babel/preset-react"],
  "plugins": ["@babel/transform-runtime", "@babel/plugin-proposal-class-properties"]
}

 

// webpack.config.js
const path = require('path')
const HtmlWebPackPlugin = require('html-webpack-plugin')

const htmlPlugin = new HtmlWebPackPlugin({
  template: path.join(__dirname, './src/index.html'),
  filename: 'index.html'
})

module.exports = {
  mode: 'development', // development    production
  plugins: [
    htmlPlugin
  ],
  module: {
    rules: [
      // 解析 jsx 语法
      {
        test: /(\.jsx|\.js)$/,
        use: {
          loader: "babel-loader"
        },
        exclude: /node_modules/
      }
    ]
  },
  resolve: {
    extensions: ['.js', '.jsx', '.json']
  }
}

 

3.2 {}语法

  • 标签必须封闭

  • class要写成classNamefor要写成htmlFor

  • HTML注释不能使用,只能使用注释{/* 注释 */}

  • 原生标签比如p、li、div如果要使用自定义属性,必须用data-前缀

  • {}中执行js表达式

const num = 100 // 数字
const str = 'react 学习' // 字符串
const bool = true // 布尔值
const unde = undefined // undefined
const nu = null // null
const h4dom = 

这是一个h4标签

// jsx 语法 // 遍历数组 const arrDom = [
这是一个h5标签1
,
这是一个h5标签2
,
这是一个h5标签3
] // 字符串数组 const arr = ["白板","幺鸡","二条","三饼"] ReactDOM.render(
{ num + 1 } - { str } - { bool.toString() } - { unde } - { nu }

这是一个h3标签


{/* 数组会自动展开 */} { h4dom } { arrDom }
    { arr.map((item,index)=>
  • { item }
  • ) }
, document.getElementById('app'))
  • 可以运行函数:render() { {this.func('参数')} }

  • 样式使用双大括号

这是一个标签

4. 创建组件

  • 组件名必须大写

  • 组件方法必须return

4.1 构造函数创建组件

import React from 'react'
import ReactDOM from 'react-dom'

// 将 person 传入 HolleWorld 组件中
// 使用 props 接收传进来的参数; props 只读,不可更改
function HolleWorld(props) {
  return 

Holle World: { props.name } - { props.age} - { props.gender }

} // 父组件传递 person 对象给 HolleWorld 子组件,必要时 HolleWorld 组件要抽离出去 const person = { name: 'Danny', age: 23, gender: 'boy' } ReactDOM.render(
{/* 组件传参 props */}
, document.getElementById('app'))

4.2 class关键字创建组件

// main.js
import React from 'react'
import ReactDOM from 'react-dom'

// 导入组件
import App from "@/App/App.jsx"

// 传递的 对象
const person = {
  name: 'Danny',
  age: 23,
  gender: 'boy'
}

//  是 Class 的实例对象
ReactDOM.render(
{ ...person }>
, document.getElementById('app'))

 

// ./App/App.jsx 抽离出来的 App 组件
import React from "react"

class App extends React.Component{
  // render函数 是渲染当前组件对应的虚拟dom元素, props 接收 父组件 传递过来的值
  render(props){
    // 通过 this.props.*** 就可以接收数据
    //返回一个jsx语法
    return 

Holle World { this.props.name } - { this.props.age} - { this.props.gender }

} } export default App

不同点:

  1. 构造函数创建出来的组件:专业的名字叫做“无状态组件”

  2. class关键字创建出来的组件:专业的名字叫做“有状态组件”

用构造函数创建出来的组件,和用class创建出来的组件,这两种不同的组件之间的本质区别就是有无state属性 和 生命周期函数! 有状态组件和无状态组件之间的本质区别就是:有无state属性!

 

5. react的样式

5.1 渲染评论列表样式

  • 行内样式

  • css样式写成js对象的形式

// main.js
import React from 'react'
import ReactDOM from 'react-dom'

import CommentList from "@/conpenents/CommentList"

ReactDOM.render(
, document.getElementById('app'))

 

// src\conpenents\CommentList.jsx
import React from "react"

import CommentDetail from "@/conpenents/CommentDetail"

class CommentList extends React.Component {
  constructor(params) {
    super()
    this.state = {
      CommentList: [
          { id: 1, user: '张三', content: '哈哈,沙发' },
          { id: 2, user: '张三2', content: '哈哈,板凳' },
          { id: 3, user: '张三3', content: '哈哈,凉席' },
          { id: 4, user: '张三4', content: '哈哈,砖头' },
          { id: 5, user: '张三5', content: '哈哈,楼下山炮' }
      ]
    }
  }
  render(props){
    return (
      
{ /* 行内样式 */}

这是评论列表组件

{ this.state.CommentList.map(item => )}
) } } export default CommentList

 

// src\conpenents\CommentDetail.jsx
import React from "react"

// 将 CSS 样式写成 js 对象的形式
import styles from '@/conpenents/styles'

function CommentDetail(props) {
  console.log(props)
  return (
    

评论人:{ props.user }

评论内容:{ props.content }

) } export default CommentDetail

 

// src\conpenents/styles
const styles = {
  itemStyle: { border: '1px dashed #ddd', margin: '10px', padding: '10px', boxShadow: '0 0 10px #ddd' },
  userStyle: { fontSize: '14px' },
  contentStyle: { fontSize: '12px' }
}

export default styles

 

使用sass

  • 第三方使用css

  • 自己的样式使用sass

配置loader

{
  test: /\.css$/,
  use: [ 'style-loader', 'css-loader']
},
{
  test: /\.scss$/,
  use: [
    { loader: 'style-loader' },
    {
      loader: 'css-loader',
      options: {
        modules: {
          localIdentName: '[path][name]-[local]-[hash:base64:5]',
        },
      }
    },
    { loader: 'sass-loader' }
  ]
}

使用:

// .jsx 文件
// 自己的 sass 文件,需要使用 sass 配置规则解析
import cssobj from '@/css/commentList.scss'
console.log('commentList.css', cssobj)

import 'bootstrap/dist/css/bootstrap.css'

class CommentList extends React.Component {
  constructor(params) {
    super()
  }
  render(props){
    return (
      
{/* 自己的 css */}

这是评论列表组件

. {/* 第三方的 css */}
) } }

 

6. react中的事件

模拟实现 VUE 中的双向绑定数据原理

//#region 介绍 react 中绑定事件的标准格式
import React from "react"

class BindEvent extends React.Component {
  constructor(params) {
    super()
    this.state = {
      msg: '哈哈',
      name: 'LiMing',
      color: '#' + Math.floor(Math.random() * 0xffffff).toString(16).padEnd(6, '0')
    }
  }
  render(props){
    return (
      

BindEvent 组件

{/* 绑定点击事件 onClick */} {/* 显示 state 中的数据 */}

{ this.state.msg }

{/* 模拟实现 VUE 中的双向绑定数据原理 */} ref="txt" style={{ width: '100%'}} value={ this.state.msg } onChange={e => this.txtChange(e) }/>
) } txtChange = (e) => { // 获取 input 中 value 的两种方法 // console.log(e.target.value === this.refs.txt.value) // true this.setState({ msg: e.target.value // this.refs.txt.value }) } myclickHandler = color => { // this.setState({}, callbcak) 是异步的,需要在 callbcak 获取最新的值 this.setState({ msg: color },() => { console.log( '2', this.state.msg ) }) // 还是未修改的值 console.log( '1', this.state.msg ) } } export default BindEvent //#endregion

 

7. react组件的生命周期函数

  • react组件的生命周期函数分为三个阶段

  • React Native 中组件的生命周期

    • 组件创建阶段:

componentWillMount:组件将要被挂载,此时还没有开始渲染虚拟DOM
render:第一次开始渲染真正的虚拟DOM,当render执行完,内存中就有了完整的虚拟DOM了
componentDidMount:组件完成挂载,此时,组件已经渲染到页面上了,数据和页面达到同步,当这个方法执行完,组件进入 运行中 的状态
    • 组件运行阶段
componentWillReceivrProps:组件将要接受新的属性,此时,只要这个方法被触发,就证明父组件为当前子组件传递了新的属性值
shouldComponenUpdate:组件是否需要被更新,此时,组件尚未开始更新,但是 state 和 props 中的数据是最新的
componentWillUpdate:组件将要被更新,此时尚未开始更新,内存中的虚拟DOM树还是旧的
render:此时,重新根据最新的 state 和 props 重新渲染一颗存在内存中的 虚拟DOM树,当 render 调用完毕,内存中旧的DOM树 替换 成新的 DOM树了,但是页面还是旧的
componentDidUpdate:此时,页面又被重新渲染了,state 和 虚拟DOM 页面都是最新的,并且保持同步
    • 组件销毁阶段
componentDidUpdate:组件将要被卸载,此时组件还可以正常使用

React 学习笔记(1) 基础语法_第1张图片

 使用计数器学习react的生命周期:

import React from "react"
import ReactTypes from 'prop-types'

class Counter extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      msg: 'ok',
      count: props.initcount
    }
  }

  // 父组件没有传递值是,设置默认值
  static defaultProps = {
    initcount: 0
  }

  // 创建静态的 propTypes 对象,可以校验 父组件传递过来的值得类型
  static propTypes = {
    initcount: ReactTypes.number // prop-types 指定数据类型
  }

  // 组件将要被挂载到页面上,此时,数据已经存在,但是还没有开始渲染虚拟DOM = VUE: created
  componentWillMount() {
    console.log('componentWillMount 函数')
    // 无法获取DOM,页面 和 虚拟DOM 还没有渲染
    console.log(document.querySelector('.myh3')) // null
    // props 和 state 可以获取到
    console.log(this.props.initcount) // 100
    console.log(this.state.msg) // ok
    this.myselfFunc()
  }

  // 渲染内存中的虚拟DOM,但是页面尚未真正显示DOM元素
  render() {
    // 每当调用 render 函数时,页面上的元素还是旧的
    console.log('render 函数')
    // return 之前,虚拟DOM还没有创建, return 之后,虚拟DOM创建,但是还没有挂载到页面上
    return (
      

这是计数器组件

this.increment} />

当前数量为:{ this.state.count }

当前数量为:{ this.props.initcount }

) } // 组件挂载到页面上,会进入这个生命周期函数,此时页面上渲染虚拟DOM了 == VUE mounted componentDidMount() { console.log('componentDidMount 函数') console.log(document.querySelector('.myh3')) //

// 使用原生js方法,改变 count 值 // document.querySelector('#btn').onclick = () => { // this.setState({ // count: this.state.count + 2 // }) // } } // 从这里判断组件是否需要更新 shouldComponentUpdate(nextProps, nextState) { console.log('shouldComponentUpdate 函数') // 该周期中必须返回一个 boolean 值 // 返回 false,则不执行其他生命周期函数,但是 state 的数据会被更改 // 返回 true,继续执行其他生命周期函数 // console.log(this.state.count) // 此时直接使用this.state是未更改的值 // console.log(nextProps, nextState) // 最新的 props 和 state // return nextState.count % 2 === 0? true: false return true } // 组件将要更新,此时尚未更新,在进入这个生命周期函数的时候,内存中的虚拟DOM是旧的,页面上的DOM元素也是旧的 componentWillUpdate() { console.log('componentWillUpdate 函数') console.log(document.querySelector('.myh3').innerText) // 旧的数据 console.log(this.refs.h3.innerText) } // 此时虚拟DOM,页面,数据都是最新的 componentDidUpdate() { console.log('componentDidUpdate 函数') console.log(this.refs.h3.innerText) } myselfFunc() { console.log('自己定义的函数'); } increment = () => { this.setState({ count: this.state.count + 1 }) } } export default Counter

使用父子组件学习componentWillReceiveProps周期函数

  • 注意:第一次渲染子组件时,componentWillReceiveProps不会传递props属性。

import React from "react"

class Parent extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      msg: '父组件中的 msg 消息'
    }
  }
  render() {
    return (

这是父组件

this.changeMsg}/>
this.state.msg }>
) } changeMsg = () => { this.setState({ msg: '更改了,变成新值了' }) } } class Son extends React.Component { constructor(props) { super(props) this.state = {} } render() { return (

这是子组件

{ this.props.pmsg }

) } // 组件接受外界传值触发 // 子组件第一次被渲染到页面上时候,不会触发这个方法,第二次以后才会触发 componentWillReceiveProps(nextProps) { console.log('被触发了') // 注意:在 componentWillReceiveProps 中拿到的值是未更改的值!! // console.log(this.props.pmsg) console.log(this.props.pmsg + '----' + nextProps.pmsg); } } export default Parent

8. react中绑定this传递参数的3中方式

import React from "react"

class BindThis extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      msg: '这是 BindThis组件中的 msg 消息'
    }

    // 绑定 this 并传参的方式 ②
    // bind 的返回值 是调用函数和参数的 copy
    // 注意:bind 不会修改原函数的 this 指向
    this.changeMsg2Copy = this.changeMsg2.bind(this, '参数one', '参数two')
  }
  render() {
    return (

这是 BindThis 组件

{/* 方式 ① */} {/* bind 修改函数内部的 this 指向,指向 bind 参数列表中的第一个参数 */} this.changeMsg1.bind(this, '参数1', '参数2')}/>
{/* 方式 ② */} this.changeMsg2Copy }/>
{/* 方式 ③ */} this.changeMsg3('参数1111', '参数2222') }/>

{ this.state.msg }

) } changeMsg1(arg1, arg2) { console.log(this) // 指向实例 this.setState({ msg: '变成新值了' + arg1 + arg2 }) } changeMsg2(arg1, arg2) { console.log(this) // undefined this.setState({ msg: '变成新值了' + arg1 + arg2 }) } changeMsg3 = (arg1, arg2) => { console.log(this) // 指向实例 this.setState({ msg: '变成新值了' + arg1 + arg2 }) } } export default BindThis

9. context多重组件传值

import React from "react"
import ReactTypes from 'prop-types'
class Conm1 extends React.Component {
  constructor(params) {
    super()
    this.state = {
      color: "red"
    }
  }

  // 1. 在父组件定义 func,这个func固定的名字 getChildContext
  // 内部必须返回一个对象,这个对象就是要共给子孙组件的数据
  getChildContext() {
    return {
      color: this.state.color
    }
  }

  // 2. 使用 属性校验,规定一下传递给子组件的数据类型,固定名字 childContextTypes
  static childContextTypes = {
    color: ReactTypes.string // 规定传递给子组件的数据类型
  }
  render(props){
    return (
      

这是父组件



) } } class Conm2 extends React.Component { render(props){ return (

这是子组件

) } } class Conm3 extends React.Component { constructor(params) { super() this.state = { } } // 3. 先来个属性校验,校验父组件传递过来的参数类型 static contextTypes = { color: ReactTypes.string // 这里,子组件一定要校验一下父组件传递过来的 context 的数据类型 } render(props){ return (
this.context.color }}>这是孙子组件 --- { this.context.color }
) } } export default Conm1

 

你可能感兴趣的:(React 学习笔记(1) 基础语法)