React基础

1 React 介绍

1.1 react

用于构建用户界面的 JavaScript 库。

react核心文件:react.development.js

react用于操作dom的扩展文件,需要依赖react核心文件:react-dom.development.js

ReactDOM.render() // 第一个参数:写入的内容,第二个参数:写入的位置
// 不允许放置到 html 和 body 标签中,会报错

1.2 虚拟DOM元素

① React.createElement()
创建虚拟的DOM元素:JSX React.createElement()
// createElement 返回的是一个虚拟的DOM对象
// 第一个参数:元素名字,第二个参数:配置属性,第三个参数:元素的内容
// h1 可以称为元素变量
const h1 = React.createElement("h1",{
    id:"my",
    className:"c1" // 会编译为class
},"你过来啊") // 虚拟对象中的 type h1,props是一个对象,存放属性;props中有个children为内容
React.render(h1,document.querySelector("div"))


// 第三个参数可以是数组
const span = React.createElement("span",{
    id:"one",
    key:"xixixi" // 可以提升 diff 算法的执行效率
},["你过来","我是一个span"])
② JSX

1.3 JSX 基本语法规范

1.3.1 JSX 元素变量或将其放置到外部

JSX 是 javascript xml,jsx是 javascript 的一个扩展,浏览器不支持,需下载 babel.min.js,支持JSX,可以将type为 text/babel 的 script 标签内出现的 JSX 转换为浏览器可识别元素。

// jsx 简化了 React.createElement 的语法结构
// jsx 是一个虚拟DOM对象,执行速度快,安全
// jsx 一般以<开头,<>当中如果是HTML标签,那么将作为HTML来处理;如果不是则会作为组件来处理
//	{}:会将{}中的内容作为js语句执行
ReactDOM.render(<h1>叫爸爸</h1>,document.querySelector("div"));
*有且只能有一个根元素
 // <><div></div></> // 只是一个包裹标签
                
// 如果内容不多建议加()
ReactDOM.render((
	<React.Fragment>
    	<div></div>
        <div></div>
    </React.Fragment>
),document.querySelector("div"))
                
// 如果内容较多,建议声明一个元素变量,值为虚拟DOM元素
const myDiv = (
    <div>
        <div>1</div>
        <p>2</p>
        <h1>1</h1>
        <h2>2</h2>
    </div>
)
ReactDOM.render(myDiv,document.querySelector("#root"))
1.3.2 {} 用法
// 1、输出变量值 <%=%>
let userName = "laotie";
ReactDOM.render((
    <div>
    <p>{userName}</p>
    <p>{"abcdefg"}</p>
    </div>
),document.querySelector("#root"));

// 2、与属性结合使用。
let imgSrc = "https://www.baidu.com/img/flexible/logo/pc/result.png";
ReactDOM.render((
    <div>
        <img src="https://www.baidu.com/img/flexible/logo/pc/result.png"/>
        <img src={"https://www.baidu.com/img/flexible/logo/pc/result.png"} />
        <img src={imgSrc}/>
	</div>
),document.querySelector("#root"))

// 3、写表达式. 简写形式(语法糖)
let num = 1;
let str = "师法魔级超";
let myDiv = <div>my</div>
let youDiv = <div>you</div>
ReactDOM.render((
    <div>
        <p>{num===1?"成功":"失败"}</p>
        <p>{str.split("").reverse().join("")}</p>
                {
                // num===1?myDiv:youDiv
                }
				{
    			/**
                 * adsf
                 */
				}
                {/* num===1 && youDiv */}
                { num===1 && myDiv}
                { num!==1 && youDiv}
	</div>
),document.querySelector("#root"));
1.3.3 className 和 style
<div>
	<p className="haha" style={{background:"red"}}>1</p>    
</div>

1.4 关于事件

注意:

如果 render 出现多次,最后一次会将前面的覆盖。

react 当中的事件与原生事件的不同:
	1.react 当中的事件需要使用小驼峰命名法
    2.取消默认事件不支持 return false,只支持 preventDefault()

给元素添加事件,可以给一个普通函数,可以给一个箭头函数,可以先定义好一个函数将函数名写在{}里,
可以定义好一个返回值是函数的函数,在{}里调用该函数,可以传参,只是会有一个事件对象。

let fn = function(){
    console.log(3333333333);
}
let fn1 = function(){
    return function () {
        console.log(444444)
    }
}
<div>
    <button  onClick={function () {
        console.log(111111111)
    }}>一</button>

    <button  onClick={()=>{
        console.log(222222222)
    }}>二</button>
    <button onClick={fn}>三</button>
    <button onClick={fn1}>四</button>

    <a href="http://www.baidu.com" onClick={function (e) {
        alert("百度")
        e.preventDefault();// 取消默认事件
    }}>百度</a>
</div>

// 小案例 显示与隐藏
let isShow = true;
let myDiv = (
    <div style={{
        width:"300px",
        height:"300px",
        background:"cyan",
        display:isShow?"block":"none"
    }}>
    </div>
)
function main(){
    ReactDOM.render((
        <div>
        <button onClick={()=>{
        isShow = !isShow;
        main();
    }}>显示与隐藏</button>
    {
    	isShow && myDiv
    }
	</div>
),document.querySelector("#root"));
}
// function main(){
//     ReactDOM.render((
//         <div>
//             <button onClick={()=>{
//                 isShow = !isShow;
//                 main();
//             }}>显示与隐藏</button>
//             <div style={{
//                 width:"300px",
//                 height:"300px",
//                 background:"cyan",
//                 display:isShow?"block":"none"
//             }}>
//             </div>
//         </div>
//     ),document.querySelector("#root"));
// }
main();

1.5 关于数组

react 当中是可以直接将数组展开的。元素是 react 中的最小单位,key 是一个字符串,可以提升执行速度。

let bookArr = ["天龙八部","啦啦啦","嘻嘻嘻"];
ReactDOM.render((
    <div>
        {
            bookArr.map((v,index)=>{
            	// return "《"+v+"》"
                return (
                    <p key={index}>《{v}》</p>
                )
        	})
        }
    </div>
),document.querySelector("#root"));

1.6 **函数组件

组件: 是对 html 元素的扩展,首字母以大写开头

模板: 由 html ,组件来组成的

组件分为两种:1、函数式组件(无状态组件)通过函数声明的组件 2、类组件(状态组件)通过类声明的组件。
	状态指的是数据。
    使用组件时可以直接闭合
定义组件的要求:
	1、首字母大写
    2、必须要有返回值,一般情况下需要返回JSX
    3、有且只能有一个根元素
    4、函数名就是组件名
    5、返回的数据即是要渲染的内容(渲染的内容即为模板 template)
 
1、函数式组件
// 复合组件 由多个组件组成的组件称为复合组件
    
// 组件传参 **重点**
    1、如何传(从上到下):通过属性向下传参 // 单向数据流
    	组件参数不允许直接修改的(5)
        修改属性是通过组件函数(6、7)props
    2、如何接收
   	3、类型限制 proptypes
   		引入 prop-types.js
    	给组件增加一个静态属性 propTypes 限制:age:PropTypes.number
		设置默认值:组件名.defaultProps

2、状态组件,需要继承React.Component:
	类名即为组件名,需要有一个 render 方法,必须有返回值
    state 状态即数据
    声明状态组件
    **修改状态的方法:this.setState({},()=>{状态修改完毕之后会执行该回调}),异步修改,修改状态之后会重新执行render函数,重新渲染
        
生命周期:钩子函数 componentDidMount

1.7 事件

事件函数:
	解决 this 为 undefined 的方案:
    	1、需要用.bind 绑定 this,可以传参,使用频率较高的话不建议使用(传参的情况比较多)
		2、构造器当中直接.bind绑定this,当不需要额外传参,且使用频率较高时建议使用
		3、直接写成箭头函数
        4、直接将函数定义为箭头函数,传值不方便

1.8 乞丐版切换和优化版切换

// 乞丐版切换
<script type="text/babel">
    class App extends React.Component{
        constructor(props){
            super(props)
            this.state = ({
                index:0
            })
        }
        changeIndex(index){
            this.setState({
                index
            })
        }
        render(){
            const {index} = this.state;
            return(
                <div className="tag">
                    <button onClick={this.changeIndex.bind(this,0)} className={index===0?"active":null}>娱乐</button>
                    <button onClick={this.changeIndex.bind(this,1)} className={index===1?"active":null}>体育</button>
                    <button onClick={this.changeIndex.bind(this,2)} className={index===2?"active":null}>军事</button>
                    <div style={{display:index===0?"block":"none"}}>娱乐新闻</div>
                    <div style={{display:index===1?"block":"none"}}>体育新闻</div>
                    <div style={{display:index===2?"block":"none"}}>军事新闻</div>
                </div>
            )
        }
    }
    ReactDOM.render((
        <App></App>
    ),document.querySelector("#root"));
</script>

// 优化版
<script type="text/babel">
    class App extends React.Component{
        constructor(props){
            super(props)
            this.state = ({
                index:0
            }),
            this.newsInfo = [
                {
                    id:1,
                    type:"娱乐",
                    newsList:[
                        {
                            id:4,
                            newsTitle:"娱乐一号"
                        },
                        {
                            id:5,
                            newsTitle:"娱乐二号"
                        }
                    ]
                },
                {
                    id:2,
                    type:"体育",
                    newsList:[
                        {
                            id:6,
                            newsTitle:"体育一号"
                        },
                        {
                            id:7,
                            newsTitle:"体育二号"
                        }
                    ]
                },
                {
                    id:3,
                    type:"军事",
                    newsList:[
                        {
                            id:8,
                            newsTitle:"军事一号"
                        },
                        {
                            id:9,
                            newsTitle:"军事二号"
                        }
                    ]
                }
            ]
        }
        changeIndex(index){
            this.setState({
                index
            })
        }
        render(){
            const {index} = this.state;
            return(
                <div className="tag">
                    {
                        this.newsInfo.map((item,i)=>(
                            <button onClick={this.changeIndex.bind(this,i)} className={this.state.index===i?"active":null}>{item.type}</button>
                        ))
                    }
                    {
                        this.newsInfo.map((item,i)=>(
                            <div key={item.id} style={{display:index===i?"block":"none"}}>
                                {
                                    item.newsList.map(info=>(
                                        <p key={info.id}>{info.newsTitle}</p>
                                    ))
                                }    
                            </div>
                        ))
                    }
                </div>
            )
        }
    }
    ReactDOM.render((
        <App></App>
    ),document.querySelector("#root"));
</script>

1.9 通过axios调用数据

<script type="text/babel">
    axios.interceptors.response.use(res=>{
        return res.data;
    })
    React.Component.prototype.$axios = axios;
    class App extends React.Component{
        constructor(props){
            super(props)
            this.state = ({
                index:0,
                newsInfo:[]
            })
        }
        changeIndex(index){
            this.setState({
                index
            })
        }
        render(){
            return(
                <div className="tag">
                    {
                        this.state.newsInfo.map((item,i)=>(
                            <button onClick={this.changeIndex.bind(this,i)} className={this.state.index===i?"active":null}>{item.type}</button>
                        ))
                    }
                    {
                        this.state.newsInfo.map((item,i)=>(
                            <div key={item.id} style={{display:this.state.index===i?"block":"none"}}>
                                {
                                    item.newsList.map(info=>(
                                        <p key={info.id}>{info.newsTitle}</p>
                                    ))
                                }
                            </div>
                        ))
                    }
                </div>
            )
        }
        componentDidMount(){
            this.$axios.get("./data.json")
            .then(newsInfo=>{
                this.setState({
                    newsInfo
                })
            })
        }
    }
    ReactDOM.render((
        <App></App>
    ),document.querySelector("#root"));
</script>

1.10 类组件

1.10.1 类组件传参
子组件接收的属性不可以直接修改;
可以通过向子组件传递函数,通过该函数进行修改,修改的其实是父组件的数据。
1.10.2 类组件的属性限制

props:属性,不允许直接修改,用于传递数据与接收数据;

state:状态,是可以修改的,在本组件中使用

子组件设置属性限制:
	给类本身添加个属性propTypes,相当于类中添加静态属性。
    defaultProps是默认属性值

1.11 ref

函数组件用于渲染较多,类组件有自己的状态,通常用于需要写一些逻辑的场景。

ref: 可以通过其获得DOM元素以及组件的实例

① ref 是一个属性,值为字符串

refs 是一个对象,对象里的内容是所有拥有ref属性的元素,对象的属性为ref的属性值

class App extends React.Component{
    render(){
        return (
            <div>
            	<div ref="one">one</div>
            	<div ref="two">two</div>
            	<input type="text" ref="userName"/>
            	<button onClick={()=>{
            	// refs:是一个对象,对象里的内容是所有拥有ref属性的元素
                    console.log(this.refs.one.innerHTML)
                    console.log(this.refs.two.innerHTML)
                    console.log(this.refs.userName.value)
                    this.refs.userName.value = "XIXI";
                    this.refs.one.style.background = "red";
        		}}>点我</button>
			</div>
		)
	}
}
② ref 是一个属性,值为箭头函数

箭头函数会在加载时执行,接收的参数即是DOM元素

class App extends React.Component{
    render(){
        return (
            <div>
                <div ref={el=>{
                    this.one = el;
                    console.log(el); // el 为<div></div>
                }}></div> 
            	<input ref={el=>this.userName=el} type="text"/> // el 为input元素

                <button onClick={()=>{
                    this.one.innerHTML = "ABCDEFG"
                    // console.log(this.one);

                    console.log(this.userName.value);
                    this.userName.value = "efg";
                }}>点我</button>
            </div>
        )
    }
}
③ 推荐使用

构造器当中设置属性,值为React.createRef(),会返回一个对象,对象中拥有属性 current,current的值就是拥有 ref 属性且值为该实例属性的元素。

// 3、ref的值是通过React.createRef()生成的。
class App extends React.Component{
    constructor(props) {
        super(props);
        this.userName = React.createRef();// 会返回一个对象,对象当中拥有属性current
    }
    render(){
        return (
            <div>
            	<div ref={this.userName}>123</div>
                <button onClick={()=>{
                    console.log(this.userName.current.innerHTML)
                }}>点我</button>
            </div>
		)
	}
}

特点:

​ 如果通过ref多次赋值,那么得到的是最后使用ref的元素,

​ 如果ref与组件结合使用,那么得到的是该组件的实例

class Child extends React.Component{
    constructor() {
        super();
        this.state = {
            a:1,
            b:2
        };
        this.age = React.createRef();
    }
    render(){
        return (
            <div>{this.state.a}|{this.state.b}
                <input type="text" ref={this.age}/>
            </div>
        )
    }
}
class App extends React.Component{
    constructor(props) {
        super(props);
        this.userName = React.createRef();// 会返回一个对象,对象当中拥有属性current
        this.arr = [1,2,3];
        this.arrRef = React.createRef();
        this.child = React.createRef();
    }
    render(){
        return (
            <div>
                <Child ref={this.child}></Child>
                <div ref={this.userName}>123</div>
                <div ref={this.userName}>456</div>
                <div ref={this.userName}>789</div>
                {
                    this.arr.map(item=>(
                        <p ref={this.arrRef} key={item}>{item}</p>
                    ))
                }
                <button onClick={()=>{
                        // console.log(this.userName.current.innerHTML) // 789
                        // console.log(this.arrRef.current) // 所在的p元素
                        console.log(this.child.current.age.current.value) // ref的值为this.age的input元素
                    }}>点我</button>
            </div>
        )
    }
}

1.12 受控组件

受控组件: 表单相对应的组件,受 react 数据状态的控制。通过 value 属性

ref 属性是 非受控组件

class App extends React.Component{
    constructor() {
        super();
        this.state = {
            userName:"laozhang",
            passWord:"",
            home:"3",
            sex:"1",
            hobby:["1","3"]
        }
    }
    changeHandler(e){
        // console.log(e.target.value)
        // console.log(e.target.name)
        let value = e.target.value;
        if(e.target.type === "checkbox"){
            const isHas = this.state[e.target.name].includes(e.target.value);
            if(isHas){
                value = this.state[e.target.name].filter(v=>v !== e.target.value)
            }else{
                value = [
                    ...this.state[e.target.name],
                    e.target.value
                ]
            }
        }
        this.setState({
            [e.target.name]:value
        })

        // if(e.target.type === "checkbox"){
        //     const isHas = this.state[e.target.name].includes(e.target.value);
        //     if(isHas){
        //         this.setState({
        //             [e.target.name]:this.state.hobby.filter(v=>v !== e.target.value)
        //         })
        //     }else{
        //         this.setState({
        //             [e.target.name]:[
        //                 ...this.state.hobby,
        //                 e.target.value
        //             ]
        //         })
        //     }
        //
        // }else{
        //     this.setState({
        //         [e.target.name]:e.target.value
        //     })
        // }

    }
    submitHandler(e){
        console.log("userName",this.state.userName);
        console.log("passWord",this.state.passWord);
        console.log("home",this.state.home);
        console.log("hobby",this.state.hobby)
        e.preventDefault();
    }
    render(){
        return (
            <form onSubmit={this.submitHandler.bind(this)} action="http://www.baidu.com">
            {/*<p>用户名:<input type="text" defaultValue={this.state.userName}/></p>*/}
                <p>用户名:<input name="userName" onChange={this.changeHandler.bind(this)} type="text" value={this.state.userName}/></p>
                <p>密码:<input
                name="passWord"
                onChange={this.changeHandler.bind(this)}
                type="password"
                value={this.state.passWord}/></p>
                <p>家乡:
                <select name="home" onChange={this.changeHandler.bind(this)}
                value={this.state.home} name="home">
                    <option value={"1"}>南白滩</option>
                <option value={"2"}>北白滩</option>
                <option value={"3"}>湖南</option>
                <option value={"4"}>湖北</option>
                </select>
                </p>
                <p>性别:
                <input onChange={this.changeHandler.bind(this)} name="sex" checked={this.state.sex==="1"} type="radio" value="1"/>男
                <input onChange={this.changeHandler.bind(this)} name="sex" checked={this.state.sex==="2"} type="radio" value="2"/>女
                </p>
                <p>
                    爱好:
                <input name="hobby" onChange={this.changeHandler.bind(this)} checked={this.state.hobby.includes("1")} type="checkbox" value="1"  />学习
                <input name="hobby" onChange={this.changeHandler.bind(this)} checked={this.state.hobby.includes("2")} type="checkbox" value="2"  />游戏
                <input name="hobby" onChange={this.changeHandler.bind(this)} checked={this.state.hobby.includes("3")} type="checkbox" value="3"  />电影
                <input name="hobby" onChange={this.changeHandler.bind(this)} checked={this.state.hobby.includes("4")} type="checkbox" value="4"  />睡觉
                </p>
                <p><input type="submit" value="提交" /></p>
            </form>
        )
    }
}

2 生命周期

2.1 旧图

生命周期: 组件从创建到销毁的过程。在生命周期当中所暴露出来的函数称为钩子函数

钩子函数: 并不是人为触发的,执行到某一个阶段的时候自动触发,只要声明了函数到指定阶段自动会执行。

生命周期分为三个阶段:

① 挂载阶段 mounting

1、2、4在生命周期中只会执行一次

1. constructor() // 构造器
2. componentWillMount() // 挂载之前 在后续某个版本中可能会被废弃掉,去除警告加前缀:UNSAFE
3. render() // 指定渲染的内容
4. componentDidMount() // 界面内容渲染完成

2 中可以编写同步代码
② 更新阶段 updating
  • 更新属性
1. componentWillReceiveProps(nextProps) // 当属性发生变化时 UNSAFE_
2. shouldComponentUpdate(nextProps) // 根据返回值决定是否允许更改界面
3. componentWillUpdate(nextProps) // 更新之前
4. render() // 指定渲染的数据
5. componentDidUpdate(prevProps) // 更新完成
class Child extends React.Component{
    constructor() {
        super();
        this.userName = React.createRef();
    }
    // 更新 nextProps:是即交要更新的值
    UNSAFE_componentWillReceiveProps(nextProps){
        console.log("1、componentWillReceiveProps");
        console.log(this.props.age,nextProps.age) // 12 13
    }
    // 必须要返回一个布尔值。true允许修改,false不允许更改
    shouldComponentUpdate(nextProps){
        console.log("2、shouldComponentUpdate");
        if(nextProps.age >15){
            return false
        }
        console.log(this.props.age,nextProps.age) // 12 13
        return true;
    }
    UNSAFE_componentWillUpdate(nextProps){
        console.log("3、componentWillUpdate");
        console.log(this.props.age,nextProps.age) // 12(更新之前的值) 13(即将更改的值)
    }
    UNSAFE_componentWillMount(){
        console.log("UNSAFE_componentWillMount")
    }
    render(){
        console.log("4、render",this.props.age) // 初始渲染12,状态发生改变时会变化
        return (
            <div>
                我还是一个孩子,今年{this.props.age}岁了
                <div ref={this.userName} >123123123123</div>
            </div>
        )
    }
    componentDidMount(){
        console.log("componentDidMount")
    }
    componentDidUpdate(prevProps){
        console.log("5、componentDidUpdate")
        // this.props.age:更新以后的值  prevProps:更新之前的值
        console.log(this.props.age,prevProps.age,this.userName.current.innerHTML)

    }
}
class App extends React.Component{
    constructor() {
        super();
        this.state = {
            age:12
        }
    }
    render(){
        return (
            <div>
                App
                <Child age={this.state.age}></Child>
                <button onClick = {()=>{
                        this.setState({
                            age:this.state.age+1
                        })
                    }}>修改age</button>
            </div>
        )
    }
}
  • 更新状态
1. shouldComponentUpdate()
2. componentWillUpdate()
3. render()
4. componentDidUpdate()
class Child extends React.Component{
    constructor() {
        super();
        this.state = {
            num:0
        }
        this.userName = "你好";
    }
    // componentWillReceiveProps(){
    //     console.log("componentWillReceiveProps")
    // }
    shouldComponentUpdate(nextProps,nextState){
        console.log("1、shouldComponentUpdate")
        console.log(this.state.num,nextState.num)
        return true;
    }
    UNSAFE_componentWillUpdate(nextProps,nextState){
        console.log("2、componentWillUpdate");
        console.log(this.state.num,nextState.num)
    }
    render(){
        console.log("3、render")
        return (
            <div>
                <button onClick={()=>{
                        this.userName = "我也好";
                        // 当你的数据没有存放在this.state当中。
                        this.forceUpdate();// 强制更新,会跳过shouldComponentUpdate

                        // this.setState({
                        //     num:this.state.num+1
                        // })
                    }}>{this.userName}|{this.state.num}</button>
            </div>
        )
    }
    componentDidUpdate(prevProps,prevState){
        console.log("4、componentDidUpdate")
        console.log(this.state.num,prevState.num);// 当前值    更新之后的值
    }
}
class App extends React.Component{
    render(){
        return (
            <div>
                <Child></Child>
            </div>
        )
    }
}
在事件中强制更新的话只会执行componentWillUpdate()、render()、componentDidUpdate()
③ 销毁阶段 unmounting
componentWillUnmount() // 销毁
class Child extends React.Component{
    constructor() {
        super();
        this.state = {
            num:0
        }
    }
    render(){
        return (
            <div>我还是一个孩子,今年{this.state.num}岁了</div>
        )
    }
    componentDidMount(){
        this.timer = setInterval(()=>{
            console.log("111111111")
            this.setState({
                num:this.state.num+1
            },function () {
                console.log(this.state.num);
            })
        },1000)
    }
    componentWillUnmount(){
        console.log("componentWillUnmount");
        clearInterval(this.timer);
    } // 虽说被销毁了,状态没有了会报错,但是还有些东西存在,在完成挂载时设置个多次定时,当销毁后还会触发该定时器,所以在定时器中添加第二个回调可以将结束的值获取到。
}
class App extends React.Component{
    constructor() {
        super();
        this.state = {
            isShow:true
        }
    }
    render(){
        return (
            <div>
                <button onClick={()=>{
                        this.setState({
                            isShow:!this.state.isShow
                        })
                    }}>显示与隐藏</button>
                {
                    this.state.isShow && <Child/>
                }
            </div>
        )
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值