• React教程


    教程

    一、demo

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8"/>
        <title>Hello React!</title>
        <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
        <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
        <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
    </head>
    <body>
    
    <div id="example"></div>
    <script type="text/babel">
        ReactDOM.render(
            <h1>Hello, world!</h1>,
            document.getElementById('example')
        );
    </script>
    
    </body>
    </html>
    

    二、安装

    官方CDN,生成环境不要用

    <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
    <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
    <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
    

    需要3个库:

    • react.min.js React的核心库
    • react-dom.min.js react的dom相关库
    • babel.min.js 对不支持es6的浏览器的兼容

    使用npm构建环境

    教程

    三、元素渲染

    <div id="example"></div>
    <script type="text/babel">
        function tick() {
            const element = (
                <div>
                    <h2>now is {new Date().toLocaleTimeString()}</h2>
                </div>
            )
            ReactDOM.render(element, document.getElementById('example'))
        }
    
        setInterval(tick, 1000)
    
    </script>
    
    • 定义一个element,它是React的元素对象
    • 通过 ReactDOM.render,把元素渲染到dom里面
    • 渲染后,修改元素不会同步到dom,如果要修改dom,需要重新渲染,也就是调用render函数
    • element只能是const,也就是只读类型

    每次修改dom,就要重新获取元素,所以把元素的获取封装起来,就比较方便了。可以通过元素函数,或者元素类来封装。名字必须大写开头。

    元素函数

    function Clock(props) {
         return (
             <div>
                 <h2>now is {props.date.toLocaleTimeString()}</h2>
             </div>
         );
     }
    
     function tick() {
    
         ReactDOM.render(<Clock date={new Date()}/>, document.getElementById('example'));
    
     }
    
     setInterval(tick, 1000);
    
    • 定义了获取元素的函数Clock
    • 通过<Clock date={new Date()}/>,这个代码会执行Clock函数,然后把入参存在函数的props属性

    元素类

    除了可以封装为函数外,也可以封装为类。

    class Clock extends React.Component {
        render() {
            return (
                <div>
                    <h2>now is {this.props.date.toLocaleTimeString()}</h2>
                </div>
            );
        }
    }
    
    function tick() {
    
        ReactDOM.render(<Clock date={new Date()}/>, document.getElementById('example'));
    
    }
    
    • 定义Clock类,继承React.Component
    • 定义render返回元素对象
    • 通过this.props访问props属性
    • 调用方法和函数一样,都是<Clock date={new Date()}/>

    四、JSX

    React使用JSX来代替js
    JSX是很像XML的js语法拓展
    JSX优点:

    1. 执行更快
    2. 类型安全,会检查编译错误
    3. 使用模板更加快捷简单

    JSX是用来在js语法中,声明React的元素的(也就是html代码),但是又不像字符串。

    
    var arr = [
        <h1>h111</h1>,
        <h2>h222</h2>,
        3
    ]
    var style = {
        fontSize: 100,
        color   : 'blue'
    }
    const element1 = <h1>
        <p style={style} font='1px' data-myattribute="kevinlu">{1 + 1},{1 == 1 ? 2 : 3}</p>
        element1
        {/*注释...*/}
        <div>{arr}</div>
    </h1>
    
    function tick() {
        ReactDOM.render(element1, document.getElementById('example'));
    
    }
    
    • 这样就声明了一个元素element1 ,但是又不需要用引号包裹。声明时可以换行。最外层只能是一个标签
      • 例如这样是不行的:const ele = <p>1</p><p>2</p>因为最外层有2个标签
      • 这样可以:const ele = <div><p>1</p><p>2</p></div>,通过外层加一个div标签。
    • 如果要定义自定义属性,可以:<p font='15pt' data-myattribute = "kevinlu"></p>data-前缀
    • 可以在元素中使用js表达式,用{}包裹
    • 不支持if else,但可以用三元运算符{i == 1 ? 'True!' : 'False'}
    • 支持内联样式,把样式定义在一个字典里面,然后再元素里引用字典
    • 支持数组,数据里面的元素可以是元素,元素会被逐一展示

    五、组件

    一个元素可以以组件形式被另一个元素引用,而且可以传参数。

    function Con(props) {
        return (
            <div>
                <h2>I am Con name={props.name}</h2>
            </div>
        );
    }
    
    
    const ele = <div><Con name="kevinlu"></Con><h3>content</h3></div>
    
    
    ReactDOM.render(ele, document.getElementById('example'));
    
    • Con是一个组件,通过props.name获取入参。组件也可以用类的形式来定义
    • ele 是一个元素,引用了Con组件,然后传输了入参name="kevinlu"
    • 也可以创建复合组件,就是多个组件组合为一个新组件
    • 组件必须大写开头,区别于html默认标签都是小写开头

    六、组件状态

    为组件赋予状态属性,通过修改状态来动态更新DOM

    class Clock extends React.Component {
        constructor(props) { //构建函数
            super(props);
            this.state = {date: new Date()}
        }
    
        componentDidMount() {//当DOM被创建(挂载),执行该函数
            this.timerId = setInterval(() => this.tick(), 1000) //() => this.tick()相当于定义了一个箭头函数,()表示无入参
        }
    
        componentWillUnmount() { // 当DOM被删除(卸载),执行改函数
            clearInterval(this.timerId)
        }
    
        tick() {//通过setState来更新state,如果直接更新,例如this.state.date=new Date(),不会同步到DOM
            this.setState({date: new Date()})
        }
    
        render() {
            return <div>
                <h1>Time</h1>
                <h2>Now is {this.state.date.toLocaleTimeString()}</h2>
            </div>
        }
    }
    
    ReactDOM.render(
        <Clock></Clock>,
        document.getElementById('example')
    )
    
    • 执行ReactDOM.render 渲染Clock元素到
      • 生成一个Clock实例
      • 执行构建函数constructor
      • 执行render生成元素的html代码
      • 渲染元素的html到DOM
      • 执行componentDidMount钩子,里面设置了一个定时器,定时器ID存储在实例的变量this.timerId中
    • 定时器定时执行() => this.tick()
      • 这是一个箭头函数,直接传this.tick是不行的,因为会丢失this参数。
      • 箭头函数执行this.tick也就是Clock实例的tick函数,
      • tock函数通过setState更新Clock实例的state里面的date属性,更新为当前时间
      • setState函数会做:
        • 更新变量
        • 重新这些render生成html
        • 把html更新到DOM
        • 所以如果直接更新变量,例如this.state.date=new Date(),是不会同步到DOM的
    • 当DOM被删除componentWillUnmount函数会被执行,然后删除定时器

    七、props

    类型检查,元素组件支持入参,props支持类型检查,检查入参是否符合要求,如果不符合,或早console显示warning信息。

    <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
    function Clock(props) {
        return <div>{props.name}</div>
    }
    
    Clock.propTypes = {
        name: PropTypes.string
    }
    ReactDOM.render(
        <Clock name={123}></Clock>,
        document.getElementById('example')
    )
    
    • Clock要求的name入参类型是string
    • 要加入babel文件的引入
    • 传入了number,所以警告:
    react.development.js:372 Warning: Failed prop type: Invalid prop `name` of type `number` supplied to `Clock`, expected `string`.
        in Clock
    

    支持的类型:

    	// 可以声明 prop 为指定的 JS 基本数据类型,默认情况,这些数据是可选的
    	optionalArray: React.PropTypes.array,
        optionalBool: React.PropTypes.bool,
        optionalFunc: React.PropTypes.func,
        optionalNumber: React.PropTypes.number,
        optionalObject: React.PropTypes.object,
        optionalString: React.PropTypes.string,
     
        // 可以被渲染的对象 numbers, strings, elements 或 array
        optionalNode: React.PropTypes.node,
     
        //  React 元素
        optionalElement: React.PropTypes.element,
    

    八、事件

    元素里面的事件,需要调用函数来触发。

    class Toggle extends React.Component{
        constructor(props){
            super(props);
            this.state={isToggleOn:true}
            this.handleClick=this.handleClick.bind(this) //需要绑定this
        }
        handleClick(){
            this.setState({isToggleOn:!this.state.isToggleOn})
        }
        render(){
            return <button onClick={this.handleClick}>
                {this.state.isToggleOn?'ON':'OFF'}
            </button>
        }
    
    }
    ReactDOM.render(
        <Toggle></Toggle>,
        document.getElementById('example')
    )
    
    • 这里写了一个开关功能,点击变ON,再次点击变OFF,以此循环。
    • 设置buttom的 onClick={this.handleClick},表示当buttom被点击,会调用handleClick函数
    • 这里需要事先为handleClick函数绑定this,否则在handleClick函数里面访问this会返回undefined,而不是Toggle的实例

    不需要绑定this的方法

    方法1:

    class ToggleTest extends React.Component {
        handleClick = () => {
            console.log('this is ', this)
        }
    
        render() {
            return <button onClick={this.handleClick}>xxx</button>
        }
    }
    ReactDOM.render(<ToggleTest ></ToggleTest >,document.getElementById('example'))
    
    • 修改定义handleClick 的方法,加上() =>,这个叫:属性初始化器语法

    方法2:

    class ToggleTest extends React.Component {
        handleClick ()  {
            console.log('this is ', this)
        }
    
        render() {
            return <button onClick={(e)=>this.handleClick(e)}>xxx</button>
        }
    }
    ReactDOM.render(<ToggleTest ></ToggleTest >,document.getElementById('example'))
    
    • onclick的时候,填入箭头函数。这里相当于重新定义了一个函数。如果向更低阶的元素组件传递函数,会重复构建函数,导致性能问题。

    传递参数

    class ToggleParam extends React.Component {
        handleClick(name, e) { // e是React的事件实例,需要放在最后面
            alert(name)
        }
        handleClick1(name) { // 也可以不要e参数
        }
    
        render() {
            return <button onClick={this.handleClick.bind(this, 'kevinlu')}>xxx</button>
        }
    }
    ReactDOM.render(<ToggleParam></ToggleParam>,document.getElementById('example'))
    
    • e是React的事件实例,需要放在所有参数最后面,也可以不设置e参数。
    • 这里通过bind的方法,绑定this和name参数,bind会返回一个新函数,当按钮被点击,React会调用该函数
    • 可以通过e.preventDefault();来阻止默认的操作。例如点击链接会跳转到新页面,这个命令可以阻止跳转操作。

    九、条件渲染

    1. if条件判断

    function If(props) {
        if (props.isLogin) {
            return <h1>is Login</h1>
        } else {
            return <h1>is not Login</h1>
        }
    }
    
        class Login extends React.Component {
            constructor(props) {
                super(props);
                this.state = {isLogin: false}
            }
    
            login() {
                this.setState({isLogin: true})
            }
    
            logout() {
                this.setState({isLogin: false})
            }
    
            render() {
                if (this.state.isLogin)
                    return <div>now is login <button onClick={this.logout.bind(this)}>logout</button></div>
                else
                    return <div>now is logout <button onClick={this.login.bind(this)}>login</button></div>
            }
    
        }
    ReactDOM.render(<If isLogin={false}></If>, document.getElementById('example'))
    
    • If和Login两个元素组件,都是根据属性,来判断render的返回html

    2.&&运算符

    function At(props) {
        return <div>kkkkk {props.number > 0 && <h2>number is {props.number} </h2>}</div>
    }
    
    • 如果props.number,显示元素<h2>number is {props.number} </h2>

    3. 三目运算符

    和IF类似,不过它可以在元素里面通过{}的方式定义:{props.number ?"large 0":'least 0'}

    4. 阻止渲染

    直接让元素组件返回null,就不会渲染这个元素。

    function NoneTest(props) {
        if (props.number > 0)
            return <div>number is {props.number}</div>
        else
            return null
    }
    

    十、数组

    var l = [1, 2, 3, 4, 5]
    const ele = <ul>
        {l.map(
            (number) => <li key={number}>{number}</li>
        )}
    </ul>
    ReactDOM.render(ele, document.getElementById('example'))
    
    • 通过JS的map方法,遍历l数组,对每个元素执行(number) => <li>{number}</li>函数,返回的是元素数组
    • 对于元素列表,React会遍历数组,逐个显示,所以url标签里面会有5个li标签
    • 数组构建的元素,需要包含一个唯一的key,不然会报错。key一般是数组元素的id,如果没有id可以用下标,即(number,index) => <li key={index}>{number}</li>

    十一、组件API

    • setState(object nextState[, function callback]) 设置状态
      *callback可选,会在修改状态后,渲染DOM后被调用
      • 没有设置的key,不会被替换
    • replaceState(object nextState[, function callback]) 替换状态
      • 和setState类似,区别是没有设置的key,会被设置为undefined
    • setProps(object nextProps[, function callback]) 设置props
    • replaceProps(object nextProps[, function callback])
    • forceUpdate([function callback]) 通知组件重绘DOM
    • DOMElement findDOMNode() 获取组件对应的DOM元素,如果没有,返回null
    • bool isMounted() 判断组件挂载状态

    十二、组件生命周期

    生命周期有:

    • Mounting 已挂载,也就是已插入到真实的DOM
    • Updating 更新中,重新渲染
    • Unmounting 已移出真实的DOM

    方法:

    • componentWillMount 组件将要挂载前调用
    • componentDidMount 组件挂载完成调用
    • componentWillReceiveProps 组件接收一个新的prop时被调用,第一次渲染不会调用。主要用户组件的更新
    • shouldComponentUpdate 返回bool值,在组件接收到新的props或者state时被调用,第一次渲染不调用
    • componentWillUpdate 在组件接收到新的props或者state但还没有render时被调用
    • componentDidUpdate 更新完成后调用,第一次渲染不调用
    • componentWillUnmount 组件被移除前调用

    十三、AJAX

    一般在componentDidMount 中通过AJAX获取数据,然后通过setState更新组件。

    class AjaxTest extends React.Component{
        constructor(props) {
            super(props);
            this.state={content:"test"}
        }
    
        componentDidMount() {
            this.req = $.get('/demo/react_demo/data', function (res) {
                this.setState({content: res})
            }.bind(this))
        }
        componentWillUnmount(){
            this.req.abort()
        }
        render(){
            return <div>{this.state.content}</div>
        }
    }
    
    • 这里用了jq的ajax方法,导入:`
    • get的回调函数需要bind this 不然回调函数里面访问this,不会执行组件实例
    • componentWillUnmount当组件被卸载,关闭http请求
      `

    十四、表单

    class Form extends React.Component {
        constructor(props) {
            super(props);
            this.state = {name: "unknow"}
        }
    
        onAttrChange(key, e) {
            var state = {}
            state[key] = e.target.value
            this.setState(state, () => console.info('new name', this.state.name))
        }
    
        render() {
            return <div>名字:<input value={this.state.name} onChange={this.onAttrChange.bind(this, 'name')}></input></div>
        }
    }
    
    • 表单的值修改后,需要通过onChange事件,更新新的值到组件的变量

    如果是嵌套组件,需要把父组件的this传给子组件

    function Input(props) {
        return <input value={props.this.state.name} onChange={props.this.onAttrChange.bind(props.this, 'name')}></input>
    }
    
    class Form extends React.Component {
        constructor(props) {
            super(props);
            this.state = {name: "unknow"}
        }
    
        onAttrChange(key, e) {
            var state = {}
            state[key] = e.target.value
            this.setState(state, () => console.info('new name', this.state.name))
        }
    
        render() {
            return <div>名字:<Input this={this}></Input></div>
        }
    }
    

    Select

    class Select extends React.Component {
        constructor(props) {
            super(props);
            this.state = {value: "unknow"}
        }
    
        onAttrChange(key, e) {
            var state = {}
            state[key] = e.target.value
            this.setState(state, () => console.info('new value', this.state.value))
        }
    
        render() {
            return <div><select value={this.state.value} onChange={this.onAttrChange.bind(this, 'value')}>
                <option value="gg">Google</option>
                <option value="fb">Facebook</option>
            </select></div>
        }
    }
    

    十五、Ref

    我们可以在元素里面的某个标签,设置一个id,然后通过ref,获取到这个标签。

    class RefTest extends React.Component {
        constructor(props) {
            super(props);
        }
    
        onClick() {
            var name = this.refs.myRef //获取到input实例
            console.info(name.value)//获取input的值
        }
    
        render() {
            return <div>
                name: <input ref="myRef"></input>
                <button onClick={this.onClick.bind(this)}>BTN</button>
            </div>
        }
    }
    
    • 这里我们为input 加了一个ref属性
    • 在onClick里,通过this.refs.myRef可以获取到这个input的实例,然后获取它的value值
  • 相关阅读:
    mongoDB知识总结
    利用js来实现一些常用的算法
    onclick和onblur的冲突问题
    GitHub 基本操作流程
    Spark UDAF实现举例 -- average pooling
    信息论基本概念
    【神经网络和深度学习】笔记
    【神经网络和深度学习】笔记
    【神经网络和深度学习】笔记
    【神经网络和深度学习】笔记
  • 原文地址:https://www.cnblogs.com/Xjng/p/15344022.html
Copyright © 2020-2023  润新知