React

目录

1.jsx的语法规则

2.组件

1.函数组件

2.类式组件

3.state

4.props

5.refs

6.非受控组件

7.受控组件

3.生命周期

4.Diff算法

5.路由的基本使用

1.路由组件与一般组件

3.Redirect的使用    

4.路由传参

1.params传参

2.search参数

3.state参数

5.编程式路由

6.BrowserRouter与HashRouter的区别


1.jsx的语法规则

           1.定义虚拟DOM时,不要写引号

            2.标签中混入JS表达式时要用{}

            3.样式的类名指定不要用class 要用className

            4.内联样式,要用style={{key:value}}的形式写

            5.只有一个根标签

            6.标签必须闭合

            7.标签首字母 若小写字母开头,则将该标签转为html中同名元素,若html中无该标签对应的同名元素,则报错。 若大写字母开头,react就去渲染对应组件,若组件没有定义,则报错

2.组件

1.函数组件

 function Demo(){
                console.log(this);//此处this是undefined,因为babel编译后开启了严格模式
                return <h2>我是函数组件</h2>
            }
ReactDOM.render(<Demo/>,document.getElementById('test'))

2.类式组件

 class MyComponent extends React.Component {
                render(){
// render是放在MyComponent的原型对象上的,供实例使用,this指向MyComponent的实例对象
                    return <h2>我是类组件</h2>
                }
            }
ReactDOM.render(<MyComponent/>,document.getElementById('test'))

/* 
执行了ReactDOM.render(<MyComponent/>.......之后,发生了什么?
	1.React解析组件标签,找到了MyComponent组件。
	2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。
	3.将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。
*/

3.state

 class MyComponent extends React.Component{
                // 构造器调用一次
                constructor(props){
                    super(props)
                    // 初始化状态
                    this.state={isHot:true}
                    // 解决demo中this的指向问题
                    this.weather=this.demo.bind(this) 
//自身没有demo,但是在原型上找到了demo把this(实例)传过去再赋值给this.weather(拿着原型上的demo生成一个新的挂载到实例自身上)
                }
                // render 调用1+n次 1是初始化那次,n是状态更新的次数
                render(){
           // 调用的是自身上的weather
                    return <h1 onClick={this.weather}>今天天气很{this.state.isHot?'炎热':'凉爽'}</h1>
                }
                // demo在MyComponent的原型对象上,供实例使用 
                // 由于weather是作为onClick的回调,所以不是通过实例调用的,是直接调用(window),类中的方法默认开启了局部的严格模式,所以demo中的this是undefined
                // demo 点几次调用几次
                demo(){
                    console.log(this);
                    const isHot=this.state.isHot
                    // this.state.isHot=!isHot 状态(state)不可直接更改,要借助一个内置API更改
                    this.setState({isHot:!isHot})
// 状态必须通过setState进行更新,且更新是一种合并,不是替换

                }
            }
ReactDOM.render(<MyComponent/>,document.getElementById('test'))

简写

 class MyComponent extends React.Component{
                state={isHot:true}
                render(){
                    return <h1 onClick={this.demo}>今天天气很{this.state.isHot?'炎热':'凉爽'}</h1>
                }
                // 赋值语句+箭头函数
                demo=()=>{
                    const isHot=this.state.isHot
                    this.setState({isHot:!isHot})
                }
            }
ReactDOM.render(<MyComponent/>,document.getElementById('test'))

4.props

  class Person extends React.Component{
            render(){
                const {name,age,sex}=this.props
                return(
                    <ul>
                        <li>姓名:{name}</li>
                        <li>性别:{sex}</li>
                        <li>年龄:{age}</li>
                    </ul>
                )
            }
        }
        // 对标签属性进行类型,必要性的限制
        Person.propTypes={
            name:PropTypes.string.isRequired,//限制name必传
            sex:PropTypes.string,
            age:PropTypes.number,
            speak:PropTypes.func
        }
        // 指定默认标签属性值
        Person.defaultProps={
            sex:'女',
            age:10
        }
        ReactDOM.render(<Person name="tom" speak={speak}/>,document.getElementById('test'))
        // const p={name:'tom',age:18,sex:'女'}
        // ReactDOM.render(<Person {...p}/>,document.getElementById('test'))
        function speak(){

        }
 function Person (props){
            const {name,age}=props
            return (
                <ul>
                    <li>姓名:{name}</li>
                    <li>年龄:{age}</li>
                </ul>
            )
        }
ReactDOM.render(<Person name="tom" age={12}/>,document.getElementById('test'))
        // const p={name:'tom',age:18,sex:'女'}
        // ReactDOM.render(<Person {...p}/>,document.getElementById('test'))
        function speak(){

        }

5.refs

class MyComponent extends React.Component{
        //     showdata=()=>{
        //         const {input1}=this.refs
        //         alert(input1.value)
        //     }
        //     onblur=()=>{
        //         const {input2}=this.refs
        //         alert(input2.value)
        //     }
        //     render(){
        //     return(
        //         <div>
        //             <input ref="input1" type="text" placeholder="点击按钮提示"/>&nbsp;
        //             <button onClick={this.showdata}>点我提示左侧的数据</button>&nbsp;
        //             <input ref="input2" onBlur={this.onblur} type="text" placeholder="失去焦点提示"/>
        //         </div>
        //     )
        //    }

        //    showdata=()=>{
        //        const {input1}=this
        //        alert(input1.value)
        //     }
        //     onblur=()=>{
        //         const {input2}=this
        //         alert(input2.value)
        //     }
        //     render(){
        //     return(
        //         <div>
        //             <input ref={(currentNode)=>{this.input1=currentNode}} type="text" placeholder="点击按钮提示"/>&nbsp;
        //             <button onClick={this.showdata}>点我提示左侧的数据</button>&nbsp;
        //             <input ref={currentNode=>this.input2=currentNode}  onBlur={this.onblur} type="text" placeholder="失去焦点提示"/>
        //         </div>
        //     )
        //    }

          // React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点
           myRef=React.createRef()
           myRef2=React.createRef()
            showdata=()=>{
               alert(this.myRef.current.value)
            }
            // 发生事件的DOM元素和操作的DOM元素都是input输入框,input发生onblur,提示input数据 ref可以省略
            onblur=(e)=>{
                alert(e.target.value)
            }
            render(){
            return(
                <div>
                    <input ref={this.myRef} type="text" placeholder="点击按钮提示"/>&nbsp;
                    <button onClick={this.showdata}>点我提示左侧的数据</button>&nbsp;
                    <input onBlur={this.onblur} type="text" placeholder="失去焦点提示"/>
                </div>
                
            )
           }
        }
ReactDOM.render(<MyComponent/>,document.getElementById('test'))

6.非受控组件

class MyComponent extends React.Component{
            handleSubmit=(e)=>{
                e.preventDefault()//阻止表单提交
                const {username,password}=this
                alert(`你输入的用户名是:${username.value},密码是:${password.value}`)
            }
            render(){
                return(
                    <form action='http://www.atguigu.com' onSubmit={this.handleSubmit}>
                        用户名:<input ref={c=>this.username=c} type="text" name="username"/>
                        密码:<input ref={c=>this.password=c} type="password" name="password"/>
                        <button>登录</button>
                    </form>
                )
            }
        }
 ReactDOM.render(<MyComponent/>,document.getElementById('test'))

7.受控组件

 class MyComponent extends React.Component{
        state={
            username:'',
            password:''
        }
        // 保存到状态中
       saveFormData=(dataType,e)=>{
            this.setState({[dataType]:e.target.value})
        }
        handleSubmit=(e)=>{
            e.preventDefault()//阻止表单提交
            console.log(e);
            const {username,password}=this.state
            alert(`你输入的用户名是:${username},密码是:${password}`)
        }
       render(){
            return(
                <form onSubmit={this.handleSubmit}>
                    用户名:<input onChange={e=>this.saveFormData('username',e)} type="text" name="username"/>
                    密码:<input onChange={e=>this.saveFormData('password',e)} type="password" name="password"/>
                    <button>登录</button>
                </form>
            )
        }
ReactDOM.render(<MyComponent/>,document.getElementById('test'))

3.生命周期

1.初始化阶段: 由ReactDOM.render()触发---初次渲染

    1.constructor()

    2.getDerivedStateFromProps

    3.render()

    4.componentDidMount() =====> 常用

    一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息

2.更新阶段: 由组件内部this.setSate()或父组件重新render触发

    1.getDerivedStateFromProps

    2.shouldComponentUpdate()

    3.render()

    4.getSnapshotBeforeUpdate

    5.componentDidUpdate()

3.卸载组件: 由ReactDOM.unmountComponentAtNode()触发

    1.componentWillUnmount()  =====> 常用

    一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息

  class Count extends React.Component{
                // 构造器
                constructor(props){
                    console.log('constructor');
                    super(props)
                    this.state={count:0}
                }
                add=()=>{
                    const {count}=this.state
                    this.setState({count:count+1})
                }
                death=()=>{
                    ReactDOM.unmountComponentAtNode(document.getElementById('test'))
                }
                // 强制更新按钮
                force=()=>{
                    this.forceUpdate()
                }
                static getDerivedStateFromProps(props){
                    console.log('getDerivedStateFromProps',props);
                    return null  //即 state 的值在任何时候都取决于 props。
                }
                getSnapshotBeforeUpdate(){
                    console.log('getSnapshotBeforeUpdate');
                    return '111'
                }
                // 组件挂载完
                componentDidMount(){
                    console.log('componentDidMount');
                }
                // 组件将要卸载
                componentWillUnmount(){
                    console.log('componentWillUnmount');
                }
                // 控制组件更新的‘阀门’
                shouldComponentUpdate(){
                    console.log('shouldComponentUpdate');
                    return true
                }
                // 组件更新完毕
                componentDidUpdate(preProps,preState,snapshotValue){
                    console.log('componentDidUpdate',preProps,preState,snapshotValue);
                }

                render(){
                    console.log('render');
                    return(
                        <div>
                            <h2>当前求和{this.state.count}</h2>
                            <button onClick={this.add}>按钮</button>
                            <button onClick={this.death}>按钮</button>
                            <button onClick={this.force}>按钮</button>
                        </div>
                    )
                }
            }
            ReactDOM.render(<Count count="199"/>,document.getElementById('test'))

4.Diff算法

 经典面试题:

      1).react/vue中的key有什么作用?(key的内部原理是什么?)

      2).为什么遍历列表时,key最好不要用index?

        1.虚拟DOM中key的作用:

            1).简单的说: key是虚拟DOM对象的标识, 在更新显示时key起着极其重要的作用。

            2).详细的说: 当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟DOM】, 随后React进行【新虚拟DOM】与【旧虚拟DOM】的diff比较,比较规则如下:

                a.旧虚拟DOM中找到了与新虚拟DOM相同的key:

                    (1).若虚拟DOM中内容没变, 直接使用之前的真实DOM

                    (2).若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM

                b.旧虚拟DOM中未找到与新虚拟DOM相同的key,根据数据创建新的真实DOM,随后渲染到到页面                        

        2.用index作为key可能会引发的问题:

            1.若对数据进行:逆序添加、逆序删除等破坏顺序操作:

                会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。

            2.如果结构中还包含输入类的DOM:

                会产生错误DOM更新 ==> 界面有问题。              

            3.注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,

                仅用于渲染列表用于展示,使用index作为key是没有问题的。                

        3.开发中如何选择key?:

            1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。

            2.如果确定只是简单的展示数据,用index也是可以的。

慢动作回放----使用index索引值作为key
			初始数据:
					{id:1,name:'小张',age:18},
					{id:2,name:'小李',age:19},
			初始的虚拟DOM:
					<li key=0>小张---18<input type="text"/></li>
					<li key=1>小李---19<input type="text"/></li>
			更新后的数据:
					{id:3,name:'小王',age:20},
					{id:1,name:'小张',age:18},
					{id:2,name:'小李',age:19},
			更新数据后的虚拟DOM:
					<li key=0>小王---20<input type="text"/></li>
					<li key=1>小张---18<input type="text"/></li>
					<li key=2>小李---19<input type="text"/></li>
	-----------------------------------------------------------------
	慢动作回放----使用id唯一标识作为key
			初始数据:
					{id:1,name:'小张',age:18},
					{id:2,name:'小李',age:19},
			初始的虚拟DOM:
					<li key=1>小张---18<input type="text"/></li>
					<li key=2>小李---19<input type="text"/></li>
			更新后的数据:
					{id:3,name:'小王',age:20},
					{id:1,name:'小张',age:18},
					{id:2,name:'小李',age:19},
			更新数据后的虚拟DOM:
					<li key=3>小王---20<input type="text"/></li>
					<li key=1>小张---18<input type="text"/></li>
					<li key=2>小李---19<input type="text"/></li>

5.路由的基本使用

1.明确好界面中的导航区、展示区

2.导航区的a标签改为Link标签  <Link to="/xxxxx">Demo</Link>

3.展示区写Route标签进行路径的匹配<Route path='/xxxx' component={Demo}/>

 4.<App>的最外侧包裹了一个<BrowserRouter>或<HashRouter>

1.路由组件与一般组件

1.写法不同:

                        一般组件:<Demo/>

                        路由组件:<Route path="/demo" component={Demo}/>

            2.存放位置不同:

                        一般组件:components

                        路由组件:pages

            3.接收到的props不同:

                        一般组件:写组件标签时传递了什么,就能收到什么

                        路由组件:接收到三个固定的属性

                                            history:

                                                        go: ƒ go(n)

                                                        goBack: ƒ goBack()

                                                        goForward: ƒ goForward()

                                                        push: ƒ push(path, state)

                                                        replace: ƒ replace(path, state)

                                            location:

                                                        pathname: "/about"

                                                        search: ""

                                                        state: undefined

                                            match:

                                                        params: {}

                                                        path: "/about"

                                                        url: "/about"

1.NavLink可以实现路由链接的高亮,通过activeClassName指定样式名

2.标签体内容是一个特殊的标签属性

3.通过this.props.children可以获取标签体内容

{/* 在React中靠路由链接实现切换组件--编写路由链接 */}
{/* <NavLink className="list-group-item" to="/about">About</NavLink>
<NavLink className="list-group-item" to="/home">Home</NavLink> */}
<MyNavLink to="/about" title="About">About</MyNavLink>
<MyNavLink to="/home" title="Home">Home</MyNavLink>
import React, { Component } from 'react'
import {NavLink} from 'react-router-dom'
export default class MyNavLink extends Component {
  render() {
    return (
        <NavLink className="list-group-item" {...this.props} />
    )
  }
}

3.Redirect的使用    

1.一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由

2.具体编码:                     

  <Switch>

       <Route path="/about" component={About}/>

        <Route path="/home" component={Home}/>

        <Redirect to="/about"/>

  </Switch>

4.路由传参

1.params传参

render() {
        const {messageArr}=this.state
        return (
            <div>
                <ul>
                    {
                        messageArr.map((msgObj) => {
                            return (
                                <li key={msgObj.id}>
                                    <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>
                                </li>
                            )
                        })
                    }
                </ul>
                <hr />
                <Route path="/home/message/detail/:id/:title" component={Detail}/>
            </div>
        )
    }
render() {
        const {id,title}=this.props.match.params
        const result=detail.find((detailObj)=>{
            return detailObj.id===id
        })
        return (
            <ul>
                <li>ID:{id}</li>
                <li>title:{title}</li>
                <li>content:{result.content}</li>
            </ul>
        )
    }

2.search参数

 render() {
        const {messageArr}=this.state
        return (
            <div>
                <ul>
                    {
                        messageArr.map((msgObj) => {
                            return (
                                <li key={msgObj.id}>
                                    <Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>
                                </li>
                            )
                        })
                    }
                </ul>
                <hr />
                <Route path="/home/message/detail" component={Detail}/>
            </div>
        )
    }
import React, { Component } from 'react'
import qs from 'qs'

const detail = [
    { id: '01', content: '1' },
    { id: '02', content: '2' },
    { id: '03', content: '3' },
]
export default class Detail extends Component {
    render() {
       const {search}=this.props.location
       const {id,title}=qs.parse(search.slice(1))

        const result=detail.find((detailObj)=>{
            return detailObj.id===id
        })
        return (
            <ul>
                <li>ID:{id}</li>
                <li>title:{title}</li>
                <li>content:{result.content}</li>
            </ul>
        )
    }
}

3.state参数

    render() {
        const {messageArr}=this.state
        return (
            <div>
                <ul>
                    {
                        messageArr.map((msgObj) => {
                            return (
                                <li key={msgObj.id}>
                                    <Link to={{pathname:'/home/message/detail',state:{id:msgObj.id,title:msgObj.title}}}>{msgObj.title}</Link>
                                </li>
                            )
                        })
                    }
                </ul>
                <hr />
                <Route path="/home/message/detail" component={Detail}/>
            </div>
        )
    }
 render() {
       const {id,title}=this.props.location.state

        const result=detail.find((detailObj)=>{
            return detailObj.id===id
        })
        return (
            <ul>
                <li>ID:{id}</li>
                <li>title:{title}</li>
                <li>content:{result.content}</li>
            </ul>
        )
    }

5.编程式路由

import React, { Component } from 'react'
import Detail from './Detail'
import { Link, Route } from 'react-router-dom'
export default class Message extends Component {
    state = {
        messageArr: [
            { id: '01', title: '消息1' },
            { id: '02', title: '消息2' },
            { id: '03', title: '消息3' },
        ]
    }
    replaceShow=(id,title)=>{
        this.props.history.replace(`/home/message/detail/${id}/${title}`)
    }
    pushShow=(id,title)=>{
        this.props.history.push(`/home/message/detail/${id}/${title}`)
    }
    forward=()=>{
        this.props.history.goForward()
    }
    back=()=>{
        this.props.history.goBack()
    }
    render() {
        const { messageArr } = this.state
        return (
            <div>
                <ul>
                    {
                        messageArr.map((msgObj) => {
                            return (
                                <li key={msgObj.id}>
                                    <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>&nbsp;&nbsp;
                                    &nbsp;<button onClick={()=>this.pushShow(msgObj.id,msgObj.title)}>push</button>
                                    &nbsp;<button onClick={()=>this.replaceShow(msgObj.id,msgObj.title)}>replace</button>
                                </li>
                            )
                        })
                    }
                </ul>
                <hr />
                <Route path="/home/message/detail/:id/:title" component={Detail} />

                <button onClick={this.forward}>前进</button>
                <button onClick={this.back}>后退</button>
            </div>
        )
    }
}

6.BrowserRouter与HashRouter的区别

1.底层原理不一样:

                        BrowserRouter使用的是H5的history API,不兼容IE9及以下版本。

                        HashRouter使用的是URL的哈希值。

2.path表现形式不一样

                        BrowserRouter的路径中没有#,例如:localhost:3000/demo/test

                        HashRouter的路径包含#,例如:localhost:3000/#/demo/test

3.刷新后对路由state参数的影响

                        (1).BrowserRouter没有任何影响,因为state保存在history对象中。

                        (2).HashRouter刷新后会导致路由state参数的丢失!!!

 4.备注:HashRouter可以用于解决一些路径错误相关的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值