11-01-react初识

本文介绍了React的基础知识,包括React的起源、特点及应用场合,并详细讲解了React的基本使用方法,如虚拟DOM的创建与渲染,以及如何通过类和函数创建组件。

react

react介绍:
起源Facebook的内部项目。13左右开源了,在github上搜索react源码。
官网:用于构建用户界面的 JavaScript 库

1)react采用组件化开发  前后端分离(管理系统)  首选react
2)react的生态比vue还好,技术非常成熟,非常适合做大型项目。
3)背景强大,react由Facebook团队维护
4)react使用比较简单,比vue难一点  api少一点
5)react可以更好理解vue   vue3.0   提升前端认知

react是最流行(世界)的框架,vue是最火(中国)框架。

react生态:
全家桶,技术栈。
    react.js            vue.js
    react-router        vue-router
    redux               vuex
    create-react-app    vue-cli
    axios               axios
    webpack             webpack
    andisn              elementui

react的基本使用:

  1. 引入react.js核心文件 ,百度react.js的CDN,下载react.js文件
  2. 引入react-dom.js 提供dom操作的react扩展库 ,百度下载
  3. 创建虚拟DOM React.createElement()
  4. 把虚拟DOM渲染到内页面 ReactDOM.render();

使用虚拟DOM方式有两种:

  • React.createElement() 不常用
  • JSX 是一个语法糖
    JavaScript and XML XML是一种自定义标签语言 ,jsx可以在HTML代码中写JS代码

基础代码

两种方式创建虚拟DOM

React.createElement()

React.createElement(1,2,3)

  • 参数1:什么样的虚拟元素 虚拟DOM(本质就是JS对象)
  • 参数2:虚拟DOM的属性
  • 参数3:虚拟DOM的内容
let vDOM = React.createElement("h1",{title:"hello react"},"你好,react")

创建一个虚拟DOM 在创建虚拟DOM时,给虚拟DOM添加class属性时,不能写class,因为class是JS的关键字。你需要写成className 就代表了class。

let content = "hello react"
let vDom1 = React.createElement("h1",{className:"box"},content);
ReactDOM.render(vDom1,document.getElementById("root1"))

JSX

在react没有模板的概念,react中的JSX类似于VUE中的模板
不能叫真实DOM,叫JSX元素,或叫JSX对象,或叫虚拟DOM

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <!--react.js是核心文件 类似于vue.js-->
    <script src="../js/react.development.js"></script>
    <!--react-dom.js提供dom操作的扩展库-->
    <script src="../js/react-dom.development.js"></script>
    <!--babel会把jsx转化成createElemtn写法-->
    <script src="../js/babel.js"></script>
</head>
<body>
    <div id="app">
    </div>
    <script type="text/babel">
        // 在react没有模板的概念,react中的JSX类似于VUE中的模板
        // 下面的代码,不能叫真实DOM,叫JSX元素,或叫JSX对象,或叫虚拟DOM
        let vDOM = (<div>
            <ul>
                <li>vue</li>
                <li>react</li>
            </ul>
        </div>)
        ReactDOM.render(vDOM,document.getElementById("app"))
    </script>
</body>
</html>

jsx中可以写表达式,不能放语句,需要用 { } 包起来,在JSX中,需要把JSX表达式放到一个{}中 才会解析,类似于vue中{{}}

 ReactDOM.render(<h1>
       <p>
           <span>{1+1}</span>
       </p>
   </h1>,document.getElementById("root"))

可以放函数调用,{}中也可以放一个函数调用

function sum(){
       return 123;
   }
   ReactDOM.render(<h1>
       <p>
           <span>{sum()}</span>
       </p>
   </h1>,document.getElementById("root"))

放三目运算符,{}也可以放一个三目运算符

let isLove = true;
ReactDOM.render(<h1>
  <p>
      <span>{isLove ? "是真爱":"是骗子"}</span>
  </p>
</h1>,document.getElementById("root"))

想在JSX中写注释 /* */
注释也是JS的内容,只要是JS的内容,都要放到{}中的
JSX中只能使用多行注释 注释也需要放到一个{}中

 let isLove = true;
 ReactDOM.render(<h1>
     <p>
         {/* 这是一个注释 */}
         <span>{isLove ? "是真爱":"是骗子"}</span>
     </p>
 </h1>,document.getElementById("root"))

在JSX中写行内样式,那样式需要写成对象的形式,对象是JS代码,需要放到{}中

 let isLove = true;
ReactDOM.render(<h1>
    <p>
        <span style={{color:"red"}}>{isLove ? "是真爱":"是骗子"}</span>
    </p>
</h1>,document.getElementById("root"))

渲染数组

 let singer=[  
    {name:"周杰伦1",age:30},
    {name:"周杰伦2",age:40},
    {name:"周杰伦3",age:50},
    {name:"周杰伦4",age:60},
]
ReactDOM.render(<ul>
    <li>{singer[0].name}</li>
    <li>{singer[1].name}</li>
    <li>{singer[2].name}</li>
    <li>{singer[3].name}</li>
    </ul>,document.getElementById("root"))

使用map映射简化数组渲染

ReactDOM.render(<ul>{singer.map((item,index)=>
  {return <li key={index}>{item.name}</li>})}</ul>,document.getElementById("root"))

循环数组

let vDOM = (
<ul>
   {
      arr.map((item,index)=><li key={item}>编号:{index+1}----姓名:{item}</li>)
   }
</ul>
)
ReactDOM.render(vDOM,document.getElementById("app"))

JSX知识点

1) JSX本质就是一个虚拟DOM,最外层,必须使用根标签包一下。
2) JSX中的标签是成对出现的,如果是单标签,也必须闭合。
3) JSX中可以放JS代码,必须放到{}中。
4) {}中可以放表达式 {1+1}  {sum()}   {10>9}  不能放语句
5) JSX中只能使用多行注释,必须使用{}包起来  {/ * xxxx * /}
6) JSX中写行内样式,必须写成对象的形式,对象必须放到{}  <h1 style={{color:"red"}}}></h1>
7) JSX中,写class属性,必须写成className,写for属性,必须写htmlFor

组件

在react中声明一个组件,有两种方式:

  • 通过class类的形式
  • 通过函数的形式

在react中为了和普通的html标签区分,组件的名字统一大写。只有大写了,react才能识别出你是一个组件。
一个组件中的jsx,必须有一个根标签。

通过类创建组件和通过函数创建组件区别:

  • 通过类创建的组件中可以放数据(状态),这类组件叫有状态组件。
  • 通过函数创建的组件不可以放数据(状态),这类组件叫无状态组件。

ReactDOM.render渲染组件的流程:

  1. 判断渲染的内容是否是组件,判定的依据首字母是否大写
  2. 如果是组件,判断出你这个组件是通过类创建的,还是通过函数创建的。
    如果是函数创建的:得到函数的返回值 函数返回jsx —> 得到虚拟DOM。
    如果是类创建的:调用render函数 render函数返回jsx —> 得到虚拟DOM
  3. 转虚拟DOM,转化成真实DOM
  4. 把真实DOM插入到挂载点 插入到真实DOM。

通过类创建组件

使用class创建组件:

  1. 内部必须实现render方法,render方法必须return一个jsx。 ----> 虚拟DOM 本质是JS对象
  2. 必须继承React.Component
  3. 组件内部的数据,也可以由外部提供,内部需要重写construtor,参数是props,props就是接收外部的数据
    还需要写super(props); 组件内部就可以使用this.props.xxx
  4. class创建的组件的数据源也可以是props。

类中的 render() 是钩子函数,不需要自己调用,react内部会在合适的时机调用
return 会返回一个jsx

使用组件

class MyHeader extends React.Component{
    render(){
        return(<div><h1>头部组件</h1></div>)
    }
}
class MyFooter extends React.Component{
    render(){
        return(<div><h1>尾部组件</h1></div>)
    }
}
class MyWraper extends React.Component{
    render(){
        return(<div>
         <MyHeader />
         <MyFooter/>
         </div>)
    }
}
ReactDOM.render(<MYWraper />,document.getElementById("root"))

组件传参

class MyComponent extends React.Component{
    constructor(props){
        super(props)
    }
    render(){
    	let style = {
                  backgroundColor:"red",
                  width:400,
                  height:400
              }
        return(<div style={sryle}>
        	<h1>它的名字:{this.props.name}</h1>
        </div>)
    }
}
// name="wangcai"  表示传递给组件内部的数据是字符串,也可以加{}
// score="[10,20,30]"  这样写,表示传递给组件内部的也是字符串
// score=[10,20,30]  这样写不对  为了[]是JS代码,需要放到{},{[10,20,30]}
ReactDOM.render(<MyComponent name={"wangxai"} score={[10,20,30]}/>,document.getElementById("root"))
</script>

接收的数据校验,设置默认值
在头部标签< head >需要引入校验js文件,prop-types.js

<script src="../js/prop-types.js"></script>

class Shop extends React.Component{
  constructor(props) {
       super(props);
   }
   /*static propTypes = {
       name:PropTypes.number.isRequired
   }*/
   static defaultProps = {
       name:"wangcai"
   }
   render(){
       return(
           <div>
               <a href={this.props.link}>{this.props.name}</a>
           </div>
       )
   }
}
// ReactDOM.render(<Shop name="JD" link="http://www.baidu.com"/>,document.getElementById("root"))
ReactDOM.render(<Shop link="http://www.baidu.com"/>,document.getElementById("root"))

通过函数创建组件

使用函数创建组件:

  1. 必须return一个JSX 因为要根据JSX获取到一个虚拟DOM。
  2. 在使用此组件时,可以给组件内部传递数据,函数可以通过形参props来接收数据。
  3. 一个组件内部需要使用数据,我们可以在外面传入。一个组件的数据源可以是props

使用组件

 // 不管是什么方式创建组件,组件名一定要大写
function Header(){ // 你要当成普通的组件,需要在函数中返回一个jsx
    return(
        <div>
            <h1>我是header组件</h1>
        </div>
    )
}
ReactDOM.render(<Header />,document.getElementById("root"))

组件传参

function MyComponet(props){  // 问:JS的function中有this吗? 答:有  因为JS中的function也可以是类
  return(
      <div>
          <h2>它的名字是:{props.name},年龄是:{props.age},分数是:{props.score}</h2>
      </div>
  )
}
ReactDOM.render(<MyComponet name="xq" age={100} score={["a","b"]} />,document.getElementById("root"))

组件是虚拟DOM的集合

function Artical() {
    return(
        <div>
            <Header/>
            <Content/>
            <Footer/>
        </div>
    )
}

接收数据校验,指定默认值
需要引入校验js文件,prop-types.js

<script src="../js/prop-types.js"></script>    

function Shop(props){
    return(
        <div>
            <a href={props.link}>{props.name}</a>
        </div>
    )
}
Shop.propTypes={
    name:PropTypes.string.isRequired,
    link:PropTypes.string.isRequired
}
ReactDOM.render(<Shop name="淘宝网" link="http://www.taobao.com" />,document.getElementById("root"))
 Shop.defaultProps={
   name:"JD",
   link:"http://www.jd.com"
}
 ReactDOM.render(<Shop />,document.getElementById("root"))

组件的状态state

  • 使用函数创建组件里面是没有state的,这类组件我们叫无状态组件。
  • 使用class创建组件里面是可以有state的,这个组件我们叫有状态组件。

一个组件的数据源:

  • 对于函数创建组件,数据源是props。
  • 对于class创建的组件,数据源可以是props,也可以是state。

对于class创建的组件,state是核心,有人也把react组件当成一个状态机。
不需要外面输入数据,类似于vue中的data。

状态的使用

class Person extends React.Component{
  constructor(props) {
      super(props);

      // 状态机
      this.state = {  // this.state是给创建出来的对象添加一个私有属性
          name:"wangcai",
          age:100,
          sex:"男",
          friend:"xiaoqiang"
      }
  }
  render(){
      return(
          <div>
              <h2>个人介绍</h2>
              <p>姓名:{this.state.name}, 年龄:{this.state.age}, 性别:{this.state.sex},朋友:{this.state.friend}</p>
              <p>--------------------</p>
              <button onClick={()=>this._dealChangePerson()}>换一个人</button>
          </div>
      )
  }
  _dealChangePerson(){
      // 更新状态机   当状态变化了,会自动调用render
      this.setState({
          name:"xiaohua",
          age:100,
          sex:"女",
          friend:"xiaohong"
      })
  }
}

ReactDOM.render(<Person />,document.getElementById("root"))

props和state共存

class Person extends React.Component{
  constructor(props) {
       super(props);
       // 状态机
       this.state = {  // this.state是给创建出来的对象添加一个私有属性
           name:"wangcai",
           age:100,
           sex:"男",
           friend:"xiaoqiang"
       }
   }
   render(){
       return(
           <div>
               <h2>个人介绍(state中的数据)</h2>
               <p>姓名:{this.state.name}, 年龄:{this.state.age}, 性别:{this.state.sex},朋友:{this.state.friend}</p>
               <button onClick={()=>this._dealChangePerson1()}>换一个人</button>
               <p>--------------------------------------</p>
               <h2>个人介绍(props中的数据,不要直接修改props接收的数据)</h2>
               <p>姓名:{this.props.personObj.p_name}, 年龄:{this.props.personObj.p_age}, 性别:{this.props.personObj.p_sex},朋友:{this.props.personObj.p_friend}</p>
               <button onClick={()=>this._dealChangePerson2()}>换一个人</button>
           </div>
       )
   }
   _dealChangePerson1(){
       // 更新状态机   当状态变化了,会自动调用render
       this.setState({
           name:"xiaohua",
           age:100,
           sex:"女",
           friend:"xiaohong"
       })
   }
   _dealChangePerson2(){
       /* this.setProps({  // 没有setProps
           p_name : "xxxxx"
       })*/
       // this.props.personObj.p_name = "xxxxx"
   }
}
let outData = {
   p_name:"xiaobai",
   p_age:666,
   p_sex:"女",
   p_friend:"xiaohei"
}
ReactDOM.render(<Person personObj={outData}/>,document.getElementById("root"))

如果要props中的数据时,因为props中的数据不能直接修改,需要将数据传到内部的state中,然后修改state的数据

class Person extends React.Component{
  constructor(props) {
    super(props);
    let {p_name,p_age,p_sex,p_friend} = this.props.personObj;
    // 状态机  把接收到的数据给state
    this.state = {  // this.state是给创建出来的对象添加一个私有属性
       name:p_name,
       age:p_age,
       sex:p_sex,
       friend:p_friend
   }
}
render(){
   let {name,age,sex,friend} = this.state
   return(
       <div>
           <h2>个人介绍</h2>
           <p>姓名:{name}, 年龄:{age}, 性别:{sex},朋友:{friend}</p>
           <button onClick={()=>this._dealChangePerson()}>换一个人</button>
       </div>
   )
}
_dealChangePerson(){
   // 更新状态机   当状态变化了,会自动调用render
   this.setState({
       name:"xiaohua",
       age:100,
       sex:"女",
       friend:"xiaohong"
   })
 }
}
let outData = {
	p_name:"xiaobai",
	p_age:666,
	p_sex:"女",
	p_friend:"xiaohei"
}
ReactDOM.render(<Person personObj={outData}/>,document.getElementById("root"))

组件数据校验

通过prop-types.js进行校验

对于函数创建的组件校验方式:

 Shop.propTypes={
    name:PropTypes.string.isRequired,
    link:PropTypes.string.isRequired
}

对于class创建的组件校验方式:

static propTypes = {
    name:PropTypes.number.isRequired
}

计算器案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="../js/react.development.js"></script>
    <script src="../js/react-dom.development.js"></script>
    <script src="../js/prop-types.js"></script>
    <script src="../js/babel.js"></script>
</head>
<body>
    <div id="root"></div>
    <script type="text/babel">
        // HTML  CSS  JS
        class Counter extends React.Component{
            static propTypes = {
                step:PropTypes.number
            }
            static defaultProps = {
                step:1
            }
            constructor(props) {
                super(props);
                // 定义一个状态机
                this.state = { res:0 }
            }
            render(){
                let { res } = this.state
                let { step } = this.props;
                return(
                    <div>
                        <h3>结果是:{res}</h3>
                        <a href="http://www.baidu.com" onClick={(e)=>this._addNum(step,e)}>{step}</a>
                        <p>-------------------------</p>
                    </div>
                )
            }
            _addNum(step,e){
                e.preventDefault(); // 阻止默认事件
                // 更新状态机
                this.setState({
                    res:this.state.res+step
                })
            }
        }
        let vDom = (
            <div>
                <Counter step={1}/>
                <Counter step={2}/>
                <Counter step={3}/>
                <Counter />
            </div>
        )
        ReactDOM.render(vDom,document.getElementById("root"))
    </script>
</body>
</html>

表单数据处理

想获取输入框中的内容:

  1. 方式1:把非受控的输入框,变成受控的输入框,获取内容就是获取状态

  2. 方式2:获取DOM元素 input
    传统操作:document.getelementByid(“input”); 不推荐的
    ref,可以给dom元素起一个ref名字,通过this.

修改非控输入框

不受控的输入框:它里面的内容不受状态的控制

<input type="text" />     

受控的输入框: 受状态的控制,输入框显示状态的内容,不能发生改变

  <input type="text" value={this.state.content} />

修改非控输入框

class Add extends React.Component{
    constructor(props){
        super(props)
      //定义了一个状态机
        this.state={
            content:"默认内容"
        }
    }
    render(){
        return(
          <div>
              非受控的:<input type="text" />
              受控的:<input 
                      type="text" value={this.state.content} 
                       onChange={(e)=>this._dealChange(e)} />
              <h3>{this.state.content}</h3>
          </div>
        )
    }
    //当输入框中的内容发生改变,会调用change事件
    _dealChange(e){
      //   更新状态机
        this.setState({
            content:e.target.value
        })
    }
}
ReactDOM.render(<Add />,document.getElementById("root")) 

ref 获取DOM元素

方式一 :ref 后面跟字符串,已经淘汰了

  1. 第1步:< input ref=“item” type=“text” /> ref后面跟一个字符串
  2. 第2步:this.refs.item.value 获取输入框中的数据
class Add extends React.Component {
   constructor(props) {
       super(props)

   }
   render() {
       return (
           <div>
               <input ref="item" type="text" />
               <button onClick={()=>this._dealClick()}>获取dom</button>
           </div>
       )
   }
   _dealClick(){
       console.log(this.refs.item) //获取DOM元素
       console.log(this.refs.item.value) //获取输入框的内容
       console.log(this.refs["item"].value)
   }
}
ReactDOM.render(<Add />, document.getElementById("root")) 

方式二:
ref后面跟上一个回调函数,回调函数的参数就是当前的DOM元素

//input 是形参,这个形参就是输入框
<input ref={(input)=>{
    this.xxx = input; // 当前的DOM元素挂载到当前组件对象的xxx属性上面的
}} type="text" />
render(){
return(
   <div>
       <input ref={(input)=>{
           this.xxx = input
       }} type="text" />
       <button onClick={()=>this._dealClick()}>获取DOM元素</button>
   	</div>
	)
}
_dealClick(){
	console.log(this.xxx)
	console.log(this.xxx.value)
}

方式三:创建ref属性 常用

  1. this.ref1 = React.createRef(); ref1是一个私有属性
  2. < input ref={this.ref1} type=“text” />
  3. this.ref1.current.value 获取DOM元素中的内容
class Add extends React.Component{
   constructor(props) {
        super(props);

        // 创建一个ref
        this.ref1 = React.createRef(); // ref1是一个私有属性
    }
    render(){
        return(
            <div>
                <input ref={this.ref1} type="text" />
                <button onClick={()=>this._dealClick()}>获取DOM元素</button>
            </div>
        )
    }
    _dealClick(){
        // console.log(this.ref1.current) //DOM元素
        console.log(this.ref1.current.value)	//输入框的值
    }
}
ReactDOM.render(<Add />, document.getElementById("root"))

上面的ref的三种使用方式,都是用在html标签上面的,当前ref也可以用在组件上,
如果用在组件上,可以获取组件对象。 如果用在标签上,可以获取DOM元素。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值