• React基础


    1.介绍

    官网https://react.docschina.org/tutorial/tutorial.html

    1.1概述

    是一个用于构建用户界面的JavaScript库。

    1.2初体验

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8">
        <title>react初体验</title>
        <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
        <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
        <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
    </head>
    
    <body>
        <div id="app"></div>
        <script type="text/babel">
            const h = <h1>hello world</h1>
            ReactDOM.render(h, document.getElementById("app"))
        </script>
    </body>
    
    </html>

    运行这个html文件即可在页面看到hello world。上例中引入了3个js文件,其中react.js是核心库,react-dom.js提供了DOM的react扩展库。babel.js是把JSX语法转为纯js语法的库。需要注意的是,在script标签中使用react时,type必须是“text/babel”。

    2.JSX

    2.1JSX的定义

    在初体验中,有这样一行代码:

    const h = <h1>hello world</h1>
    

    这个标签语法既不是字符串也不是 HTML,而是被称为 JSX(全称JavaScript XML),是一个 JavaScript 的语法扩展。JSX 语法上更接近 JavaScript 而不是 HTML,所以 React DOM 使用 camelCase(小驼峰命名)来定义属性的名称,而不使用 HTML 属性名称的命名约定。当jsx有多行代码时,可以使用括号把这些jsx标签包裹起来,看起来比较规范。

    2.2在JSX中嵌入表达式

    const name = '张三'
    const h = <h1>欢迎你,{ name }</h1>

    首先声明一个名为 name 的变量,然后使用大括号包起来,就可以使用。不仅如此,还可以在大括号中放任何有效的js表达式,jsx实际上也是一个表达式。

    实例:在jsx中使用变量和方法

    function sum(a1, a2) {
        return a1 + a2
    }
    const a = 10, b = 20
    const h = <h1>求和:{a}+{b}={sum(a, b)}</h1>
    ReactDOM.render(h, document.getElementById("app"))

    2.3JSX特定属性

    在JSX中,给标签属性添加值,使用引号或大扩号,两者只能使用一个。假如一个标签里面没有内容,你可以使用 /> 来闭合标签。另外React DOM 在渲染所有输入内容之前,默认会进行转义,以确保在应用中永远不会注入那些并非自己明确编写的内容。所有的内容在渲染之前都被转换成了字符串,可以有效地防止 XSS攻击。

     1)使用引号。和原来类似,需要注意的是指定类名换成了className,而不是class。

    const h = <h1 className="myH1">hello world</h1>
    ReactDOM.render(h, document.getElementById("app"))

    2)使用大括号插入表达式

    const url='4.png'
    const img=<img src={url}/>
    ReactDOM.render(img, document.getElementById("app"))

    实例:动态的显示一个数组为li

    const arr = ['java', 'c++', 'c#', 'python']
    const ul = <ul>{arr.map((name, index) => <li key={index}>{name}</li>)}</ul>
    ReactDOM.render(ul, document.getElementById("app"))

    这里用到了数组的map方法,它会遍历数组的每一个内容,并返回操作后的内容。在使用li标签时,指定了key,即给每一个元素指定了一个唯一的标识,也就是在其兄弟节点之间应该是独一无二的。然而,它们不需要是全局唯一的。当生成两个不同的数组时,可以使用相同的 key 值,这是react要求的。效果图如下:

    2.4JSX表示对象

    Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用,然后把JSX语法转为js语法。

     以下两种示例代码完全等效:

    1)使用jsx语法

    const h = <h1 className="myH1">hello world</h1>

    2)不使用jsx语法

    const h = React.createElement(
        'h1',
        {className:'myH1'},
        'hello world'
    )

    这种语法,通过createElement函数分别指定标签名、属性对象以及内容。相比起来,这种还是麻烦的,不常用。

    3.组件

    3.1定义组件

    3.1.1函数组件

    定义组件最简单的方式就是编写 JavaScript 函数,然后在标签中使用即可,这种方式比较简单。

     <script type="text/babel">
            function Welcome() {
                return <h1>Hello, 组件</h1>;
            }
            const element = <Welcome/>
            ReactDOM.render(element, document.getElementById("app"))
     </script>

    3.1.2class组件

    当然还可以使用ES6的class来定义组件。这种方式比较复杂,非常适用于有状态的组件。

     <script type="text/babel">
            class Welcome extends React.Component{
                render(){
                    return <h1>你好啊,组件</h1>
                }
            }
            const element = <Welcome/>
            ReactDOM.render(element, document.getElementById("app"))
       </script>

    函数组件和class组件还是有区别的,最大的区别就是,在函数组件中props和方法的调用不需要this,而class组件中都需要。

    3.2组件属性state

    state叫做状态,是组件对象最重要的属性,其值是对象类型。当修改了其值,那么组件就会执行render()方法来重新渲染。如果其他组件也需要这个 state,那么可以将它提升至这些组件的最近共同父组件中。

    3.2.1操作语法

    1)初始化状态

    第一种方法

     class App extends React.Component{
                constructor(props){
                    super(props)
                    //初始化状态
                    this.state={
                        stateName:value
                    }
                }
            }

    第二种方法

     class App extends React.Component{       
         //初始化状态,不在构造函数中设置
        state={
              stateName:value
       }
    }        

    2)获取状态

    this.state.stateName

    3)修改状态。规则是状态在哪个组件,就在此组件更新状态。

     this.setState({
        stateName:value
    })

    3.2.2基本使用

    实例:通过点击按钮,来显示不同的两种值

    <script type="text/babel">
            class App extends React.Component {
                constructor(props) {
                    super(props)
                    //初始化状态
                    this.state = {
                        count: false
                    }
                    //把新添加的方法中this强制绑定为组件对象
                    this.clickEvent = this.clickEvent.bind(this)
                }
                render() {
                    //解构方式读取状态
                    const { count } = this.state
                    return (
                        <div>
                            <h2>{count ? '你好啊' : '我很好'}</h2>
                            <button  onClick={this.clickEvent}>切换</button>
                        </div>
                    )
                }
                //新添加的方法,内部的this默认不是组件对象
                clickEvent() {
                    this.setState({
                        count: !this.state.count
                    })
    
                }
            }
                //简写的方式,直接使用组件
                ReactDOM.render(<App/>, document.getElementById("app"))
        </script>

    通过点击按钮,可以来回切换内容的显示。

    需要注意的是:1)新添加的方法,内部的this默认不是组件对象而是undefined,如果要使用this,必须把这个this强制转换为组件对象。另外这个实例中出现的onClick事件,在后面会介绍。

           2)不要直接修改state的值,this.state.count=3这种方式是不正确的,也是不生效的。必须通过setState进行更新。

    在上例中,设置状态是在构造函数中进行的,也有另一种方法,在类中设置即可。

     class App extends React.Component {
          constructor(props) {
              super(props)
              //把新添加的方法中this强制绑定为组件对象
               this.clickEvent = this.clickEvent.bind(this)
           }
        //初始化状态
        state = {
               count: false
         }
        ...
    }    

    另外,在构造函数中绑定了clickEvent方法的this,其实也可以不绑定,只要把此方法通过箭头函数定义即可。这样一来,可以不使用构造函数,减少代码量。

    clickEvent = () =>  {
          this.setState({
                count: !this.state.count
         })
     }

    3.3组件属性props

    当组件进行通信时,可以使用props属性,以函数组件为例。当子组件想要使用父组件的方法时,也是可以通过props的方法,把方法名传递给子组件,然后子组件通过props来调用相应的方法即可。

    1)直接传递参数(变量)

     <script type="text/babel">
            function Welcome(props) {
                return <h1>Hello, 组件{props.name}</h1>;
            }
            const element = <Welcome name="张三"/>
            ReactDOM.render(element, document.getElementById("app"))
    </script>

    在这个例子中,定义组件时,接收了props的参数,所有的值都在里面,使用了其中的name属性。使用组件时,传入了name的值,这样就可以在组件内部使用这个name的值。 

    2)给props设置默认值

    有时候,有些参数不是必须传递的,可以通过设置默认值进行显示。

    const person = {
       name: '张三',
       age: 18,
       sex: ''
    }
    
    function Welcome(props) {
       return (
             <ul>
                  <li>姓名:{props.name}</li>
                  <li>性别:{props.sex}</li>
                  <li>年龄:{props.age}</li>
             </ul>
         )
     }
     //设置props默认值
    Welcome.defaultProps = {
                sex:'',
                age:20
    }
    const element = <Welcome name={person.name}  />
    ReactDOM.render(element, document.getElementById("app"))

    3)给props指定参数类型和必传类型

    在使用前,需要导入一个js或通过npm安装

    直接引入js

    <script src="https://cdn.bootcdn.net/ajax/libs/prop-types/15.5.10/prop-types.js"></script>

    npm安装

    npm i prop-types -S

    有些参数是必须要传递的,需要设置必须传递。也可以对传递的参数进行类型限制。

     const person = {
                name: '张三',
                age: '18',
                sex: ''
            }
     function Welcome(props) {
          return (
              <ul>
                <li>姓名:{props.name}</li>
                <li>性别:{props.sex}</li>
                <li>年龄:{props.age}</li>
              </ul>
                )
            }
            //指定属性值的类型和必传类型
      Welcome.propTypes={
           //同时指定name是string类型和必传
           name:PropTypes.string.isRequired,
           age:PropTypes.number
       }
       const element = <Welcome name={person.name} sex={person.sex} age={person.age} />
       ReactDOM.render(element, document.getElementById("app"))

    对于上面的代码,age指定的是number类型,传递的是string类型,浏览器就会报错。指定了name是必传的,如果不传也会报错。当需要传递的是一个对象的所有属性时,可以使用ES6的扩展运算符简写:

    const element = <Welcome {...person} />

     另外,如果是用class组件,那么就没有props参数,但是这个值存在this中,使用this.props同样可以获取。

    在class组件中,可以把props的类型判断放到类内部通过static修饰,不使用上面的那种方式,3的class组件如下:

    const person = {
        name: '张三',
        age: 18,
        sex: ''
    }            
    class Welcome extends React.Component {
        //指定属性值的类型和必传类型
        static propTypes = {
            //同时指定name是string类型和必传
            name: PropTypes.string.isRequired,
            age: PropTypes.number
        }
        render() {
            const props = this.props
            return (
                <ul>
                    <li>姓名:{props.name}</li>
                    <li>性别:{props.sex}</li>
                    <li>年龄:{props.age}</li>
                </ul>
            )
        }
    }
    
    const element = <Welcome name={person.name} sex={person.sex} age={person.age} />
    ReactDOM.render(element, document.getElementById("app"))
            

    当然,也可以参照此例把设置默认值放到class内部

    static defaultProps = {
        sex: '女',
        age: 20
    }

    3.4组件属性ref

    通过ref,可以找到对应的组件,即用来标识组件的某个元素。

    实例1:点击按钮,获取文本框的值

      class App extends React.Component {
          constructor(props) {
               super(props)
               //把新添加的方法中this强制绑定为组件对象
               this.clickEvent = this.clickEvent.bind(this)
          }
         render() {
              return (
                   <div>
                      <input type="text" ref={input =>this.inputValue=input}/>
                      <button  onClick={this.clickEvent}>获取值</button>
                   </div>
              )
         }
         //新添加的方法,内部的this默认不是组件对象
         clickEvent() {
             alert(this.inputValue.value)
         }
      }
      ReactDOM.render(<App/>, document.getElementById("app"))

    本例中,在input标签中添加了ref属性,里面是一个input方法。

    实例2:对组件的三个属性进行综合使用,做一个简单的数据添加,然后动态的显示

         //组件1,父组件  
    class App extends React.Component { constructor(props) { super(props) //状态中存入数据 this.state = { list: ['C++', 'python', 'C语言', 'java'] } this.addList = this.addList.bind(this) } //父组件添加数据,修改状态 addList(value) { let { list } = this.state list.unshift(value) this.setState({ list }) } render() { const { list } = this.state return ( <div> <h1>简单的数据动态显示</h1> <Add count={list.length} addList={this.addList} /> <List list={list} /> </div> ) } }

         //组件2,添加数据的组件
    class Add extends React.Component { constructor(props) { super(props) this.addHandle = this.addHandle.bind(this) } addHandle() { const val = this.inputValue.value.trim() if (val) { //调用父组件传递过来的方法 this.props.addList(val) } //清空文本框 this.inputValue.value = '' } render() { return ( <div> <input type="text" ref={input => this.inputValue = input} /> <button onClick={this.addHandle}>添加 #{this.props.count + 1}</button> </div> ) } }

         //组件3,数据展示的组件  
    class List extends React.Component { constructor(props) { super(props) } render() {
              //在class组件中,使用this.props来获取传递的参数
    const { list } = this.props return ( <div> <ul> {list.map((item, index) => <li key={index}>{item}</li>)} </ul> </div> ) } } //对传入的类型进行判断 Add.propType = { count: PropTypes.number.isRequire,
            //接收参数是函数,必传 addList: PropTypes.func.isRequire } List.propType
    = { list: PropTypes.array.isRequire }
         //渲染组件 ReactDOM.render(
    <App />, document.getElementById("app"))

    当点击添加按钮时,就会把数据添加到数组中,然后显示在页面上。截图如下:

    在这个实例中,需要注意的是,子组件是不能改变父组件的状态的。使用的数据存放在状态state中,组件之间的传值使用props,获取组件的某个元素使用ref。

    3.5组件的生命周期

    1)挂载(mount):componentDidMount()

    组件第一次渲染完成时期,此时dom节点已经生成。

    2)卸载(unmount):componentWillUnmount ()

    在此处完成组件的卸载和数据的销毁。

    实例:动态的显示系统时间,点击关闭时就清除组件内容

         class App extends React.Component {
                constructor(props) {
                    super(props)
                    //状态中存入数据
                    this.state = {
                        date: new Date()
                    }
                }
                //组件挂载时设置定时器
                componentDidMount() {
                    this.timerID = setInterval(() => {
                        this.setState({
                            date:new Date()
                        })
                    },1000);
                }
                //在卸载组件之前删除组件
                componentWillUnmount(){
                    //清除定时器
                    clearInterval(this.timerID)
                }
                //删除组件
                destoryComponent(){
                    //通过dom的id删除对应元素
                   ReactDOM.unmountComponentAtNode(document.getElementById('app'))
                }
                render() {
                    const { list } = this.state
                    return (
                        <div>
                            <h2>现在时间:{this.state.date.toLocaleTimeString()}</h2>
                            <button onClick={this.destoryComponent}>删除时间组件</button>
                        </div>
                    )
                }
            }
    
            ReactDOM.render(<App />, document.getElementById('app'))    

    本例通过ReactDOM实例的unmountComponentAtNode()方法来删除组件。

    3.6组件嵌套

    3.6.1使用props.children

    在组件中使用其他的组件,父组件内的内容将会作为children通过props传递给子组件,子组件通过children将他们的子组件到渲染结果中。
    //侧边栏,通过children将他们的子组件到渲染结果中
    function Sidebar(props) {
        return (
            <div>
                {props.children}
            </div>
        )
    }
    //在组件中使用其他的组件,组件Sidebar内的内容将会作为children通过props传递给Sidebar
    function Welcome(props) {
        return (
            <div>
                <h1>菜单栏</h1>
                <Sidebar>
                    <p>用户管理</p>
                    <p>菜单管理</p>
                    <p>系统管理</p>
                </Sidebar>
            </div>
        )
    }
    
    ReactDOM.render(<Welcome />, document.getElementById("app"))

    3.6.2自行约定

    将所需内容传入 props,并使用相应的 prop。

    function Sidebar(props) {
        return (
            <div>
                <div className="left">
                    <h2>菜单区</h2>
                    {props.left}
                </div>
                <div className="right">
                    <h2>内容区</h2>
                    {props.right}
                </div>
            </div>
        )
    }
    //通过props传递jsx
    function Welcome() {
        return (
            <div>
                <Sidebar left={<p>我是左边菜单栏</p>} right={<p>我是右边显示具体内容</p>}/>
            </div>
        )
    }
    ReactDOM.render(<Welcome />, document.getElementById("app"))

    3.7组件通信Context

    除了使用props进行组件之间的传值之外,还可以使用context进行组件之间的通信。当多个嵌套的组件之间进行传值用到同一个变量时,使用props就显得非常的冗杂。还有一种情况就是当两个兄弟组件需要使用同一数据时,目前的办法就是定义一个公共的父组件,把数据放到父组件中,也是比较麻烦的。context提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。

    3.7.1深层嵌套组件使用props案例

                  class ItemIndex extends React.Component {
                render() {
                    return (
                        <span>{this.props.index}-----</span>
                    )
                }
            }
            class DataItem extends React.Component {
                render() {
                    return (
                        <div><ItemIndex index={this.props.index} />{this.props.item}</div>
                    )
                }
            }
            class DataList extends React.Component {
                render() {
                    const { list } = this.props
                    return (
                        <ul>
                            {list.map((item, index) => <DataItem index={index} key={index} item={item} />)}
                        </ul>
                    )
                }
            }
            class Welcome extends React.Component {
                render() {
                    const list = ['C++', 'python', 'java']
                    return (
                        <DataList list={list} />
                    )
                }
            }
    
            ReactDOM.render(<Welcome />, document.getElementById("app"))            

    这个实例中组件DataItem接收了index,但是它没有使用,又传递给了ItemIndex组件,这就是层层传递的问题。

    3.7.2使用context解决

    全局定义一个context对象,然后在需要传递值的组件外部添加一个provider将值深入传递进组件树,直到在需要的地方使用。在使用时,设置context类型为全局定义的context,然后使用this.context获取。上面实例的代码替换如下:

            //创建context对象,light是默认值
            const ThemeContext = React.createContext('light')
            
            class ItemIndex extends React.Component {
                //设置context类型,使用this.context获取
                static contextType = ThemeContext
                render() {
                    return (
                        <span>{this.context}-----</span>
                    )
                }
            }
            class DataItem extends React.Component {
                render() {
                    return (
                        <div><ItemIndex />{this.props.item}</div>
                    )
                }
            }
            class DataList extends React.Component {
                render() {
                    const { list } = this.props
                    return (
                        <ul>
                            {list.map((item, index) =>
                                <ThemeContext.Provider value={index}>
                                    <DataItem key={index} item={item} />
                                </ThemeContext.Provider>)
                            }
                        </ul>
                    )
                }
            }
            class Welcome extends React.Component {
                render() {
                    const list = ['C++', 'python', 'java']
                    return (
                        <DataList list={list} />
                    )
                }
            }
    
            ReactDOM.render(<Welcome />, document.getElementById("app")) 

    效果和上面实例的效果一样。实例中context对象放在同一个js文件中,当需要在不同的js文件中使用是,就把创建context对象的代码放到一个js文件,其他文件需要时引入即可。

    3.8组件通信消息订阅发布机制

    也可以使用消息订阅(subscribe)-发布(publish)机制来解决兄弟组件传递数据的问题。

    3.8.1安装

    安装

    npm i pubsub-js -S

    导入

    import pubsub from 'pubsub-js'

    3.8.2使用

    1)订阅

    Pubsub.subscribe('messageName',function(msg,data){ })

    订阅后指定消息的名字以及回调函数,包含回调信息和数据。

    2)发布

    Pubsub.publish('messageName',data)

    指定消息的名字和要传递的数据。

    3)组件中使用

                class DataItem extends React.Component {
                state={
                    msg : '我是来自DataItem的信息'
                }
                //挂载后发布信息
                componentDidMount() {
                    Pubsub.publish('message', this.state.msg)
                }
                render() {
                    return (
                        <div>{this.state.msg}</div>
                    )
                }
            }
            class DataItem2 extends React.Component {
                state={
                    message:''
                }
                //挂载后订阅信息
                componentDidMount() {
                    Pubsub.subscribe('message', (msg, data) => {
                        this.setState({message: data})
                    })
                }
                render() {
                    return (
                        <div>我收到来自兄弟的信息:{this.state.message}</div>
                    )
                }
            }
            class Welcome extends React.Component {
                render() {
                    return (
                        <div><DataItem />
                            <DataItem2 /></div>
                    )
                }
            }
    
            ReactDOM.render(<Welcome />, document.getElementById("app"))

    4.事件处理

     React 事件的命名采用小驼峰式(camelCase),而不是纯小写。在使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。

    4.1点击事件onClick

    1)直接的点击触发

    function handleEvent(){
        alert("我是react事件")
    }
    function MyButton(){
        return <button onClick={handleEvent}>点我触发点击事件</button>
    }
    
    ReactDOM.render(<MyButton />,document.getElementById('app'))

    本例没有传递参数,实际上在事件方法中有一个默认的参数event,在需要用的时候加入即可。

    function handleEvent(e) {
        alert("我是react事件")
        console.log(e)
    }

    2)阻止默认行为

    在 React 中不能通过返回 false 的方式阻止默认行为,必须显式的preventDefault来阻止。
           //函数组件 
        function ActionLink() {
            //点击事件要执行的方法 function handleClick(e) { e.preventDefault();//阻止标签的默认行为 console.log(
    'The link was clicked.'); } return ( <a href="#" onClick={handleClick}> Click me </a> ) } ReactDOM.render(<ActionLink />,document.getElementById('app'))

    对比1和2可以看出,一个事件的触发方法是放在函数组件的外面,一个放在函数组件的里面,这都是可以的,但是在class组件中只能放在类内部。

    3)给点击事件传递参数

    点击的事件,有时也需要传递参数,有两种方式。

    第一种:使用箭头函数在方法中传递

    function handleEvent(p,e) {
       alert("我是react事件,传递参数是:" + p)
      console.log(e) } function MyButton() {
    return <button onClick={e => handleEvent(123, e)}>点我触发点击事件</button> } ReactDOM.render(<MyButton />, document.getElementById('app'))

    第二种:通过bind绑定机制传递

     function handleEvent(p, e) {
         alert("我是react事件,传递参数是:" + p)
       console.log(e) } function MyButton() {
    return <button onClick={handleEvent.bind(this,123)}>点我触发点击事件</button> }

    这两种方式效果都是一样的,只不过对于事件event,一个是显式传递,一个是隐式传递。传递后要获取事件对象event,都是通过最后一个参数来的,前面的参数是传递的形参。

    4.2内容改变事件onChange

    和原生的onchange事件同。

    5.表单

    5.1受控组件和非受控组件

    1)受控组件:表单输入的数据能够自动存到state状态中

    2)非受控组件:需要时才手动读取表单的数据

    一般情况下,都会把表单输入的数据作为受控组件使用。

    5.2input标签

    1)输入框text

        class App extends React.Component {
                constructor(props) {
                    super(props)
                    this.state = {
                        value: ''
                    }
                    //绑定this
                    this.changeHandle = this.changeHandle.bind(this)
                    this.submitHandle = this.submitHandle.bind(this)
                }
                changeHandle(event) {
                    this.setState({
                         value: event.target.value 
                    })
                }
                submitHandle(event) {
                    alert(this.state.value)
                    event.preventDefault()
                }
                render() {
                    return (
                        <form onSubmit={this.submitHandle}>
                            用户名:<input type='text' onChange={this.changeHandle} />
                            <button type="submit">提交</button>
                        </form>
                    )
                }
            }

    点击按钮时打印文本框输入的值。通过onChange事件,来不断的更新state里面的值。

    2)单选框radio

      render() {
          const {value}=this.state
          return (
             <form onSubmit={this.submitHandle}>
                性别:
                <input type='radio' name="sex" onChange={this.changeHandle} value="0" checked={value==0}/><input type='radio' name="sex" onChange={this.changeHandle} value="1" checked={value==1}/><button type="submit">提交</button>
             </form>
         )
     }

    3)复选框checkbox

    4)多文本框输入

    当需要处理多个文本框时,可以根据元素的name属性来判断event.target.name要执行的操作。

        class App extends React.Component {
                constructor(props) {
                    super(props)
                    this.state = {
                        username:'',
                        password:''
                    }
                    //绑定this
                    this.changeHandle = this.changeHandle.bind(this)
                    this.submitHandle = this.submitHandle.bind(this)
                }
                changeHandle(event) {
                    const target = event.target
                    //根据不同的name获取不同的值
                    const name = target.name
                    this.setState({
                        // 使用ES6 计算属性名称的语法更新给定输入名称对应的 state 值
                        [name]: target.value
                    })
                }
                submitHandle(event) {
                    alert(this.state.username+","+this.state.password)
                    event.preventDefault()
                }
                render() {
                    const {value}=this.state
                    return (
                        <form onSubmit={this.submitHandle}>
                            用户名:<input type='text' name="username" onChange={this.changeHandle} />
                            密码:<input type='password' name="password" onChange={this.changeHandle} />
                            <button type="submit">提交</button>
                        </form>
                    )
                }
        }

    5.3textarea标签

    在React 中,<textarea> 使用 value 属性代替子元素的文本信息。
         class App extends React.Component {
                constructor(props) {
                    super(props)
                    this.state = {
                        value: '请输入信息'
                    }
                    //绑定this
                    this.changeHandle = this.changeHandle.bind(this)
                    this.submitHandle = this.submitHandle.bind(this)
                }
                changeHandle(event) {
                    this.setState({
                        value: event.target.value
                    })
                }
                submitHandle(event) {
                    alert(this.state.value)
                    event.preventDefault()
                }
    
                render() {
                    return (
                        <form onSubmit={this.submitHandle}>
                            输入信息:<textarea onChange={this.changeHandle} value={this.state.value} />
                            <button onClick={this.submitHandle}>提交</button>
                        </form>
                    )
                }
            }

    5.4select标签

    React的select在根 select 标签上使用 value 属性来选中某个选项。

          class App extends React.Component {
                constructor(props) {
                    super(props)
                    this.state = {
                        value: '1'
                    }
                    //绑定this
                    this.changeHandle = this.changeHandle.bind(this)
                    this.submitHandle = this.submitHandle.bind(this)
                }
                changeHandle(event) {
                    this.setState({
                        value: event.target.value
                    })
                }
                submitHandle(event) {
                    alert(this.state.value)
                    event.preventDefault()
                }
    
                render() {
                    return (
                        <form onSubmit={this.submitHandle}>
                            选择性别:<select onChange={this.changeHandle} value={this.state.value}>
                                <option value="0">男</option>
                                <option value="1">女</option>
                            </select>
                            <button onClick={this.submitHandle}>提交</button>
                        </form>
                    )
                }
            }

    选择性别时,默认state是1,就选中了女,通过这种方式设置默认选中的值。

    6.条件渲染

    根据不同的值渲染不同的组件。

    6.1元素变量

    实例:根据state中变量的值,来渲染对应的组件

    class Welcome extends React.Component {
        state = {
            isLogin: false
        }
        render() {
            const { isLogin } = this.state
            //根据条件的不同,渲染不同的组件
            if (isLogin) {
                return (
                    <Login />
                )
            } else {
                return (
                    <Regist />
                )
            }
        }
    }
    class Login extends React.Component {
        render() {
            return (<div>登录页面</div>)
        }
    }
    class Regist extends React.Component {
        render() {
            return (<div>注册页面</div>)
        }
    }
    ReactDOM.render(<Welcome />, document.getElementById("app"))

    6.2与运算符&&

    前面介绍jsx的{ }时已经说明,可以在里面放任何表达式,因此可以放入&&进行运算。

    render() {
        return (
            <div>
                <h1>欢迎来到react世界</h1>
                {1 < 0 && <h2>哈哈哈</h2>}
            </div>
        )
    }

    代码中由于1<0不成立,因此不会显示h2标签的内容。

    6.3三目运算符

    根据值的不同显示不同的表达式。

    render() {
        const flag = true
        return (
            <div>
                <h1>欢迎来到react世界</h1>
                <p>用户{flag?'':''}登录</p>
            </div>
        )
    }

    6.4阻止组件的渲染

    在极少数情况下,希望能隐藏组件,即使它已经被其他组件渲染。若要完成此操作,可以让 render 方法直接返回 null,而不进行任何渲染。

    function WarningBanner(props) {
      if (!props.warn) {
        return null;
      }
    
      return (
        <div className="warning">
          Warning!
        </div>
      );
    }

    此组件会根据 prop 中 warn 的值来进行条件渲染。如果 warn 的值是 false,那么组件则不会渲染。

    7.整合axios

    整合axios非常简单,引入js,然后发送对应的请求即可。

    1)引入js

    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.1.0/axios.min.js"></script>

    使用npm安装

    npm i axios -S

    2)获取笑话的完整代码

        <script type="text/babel">
            class App extends React.Component {
                //状态中存入数据
                state = {
                    num: 10,
                    jokes: []
                }
                //组件挂载
                componentDidMount() {
                    this.getJokes()
                }
                getJokes = () => {
                    let { num, jokes } = this.state
                    console.log(num)
                    //发送异步请求
                    const url = 'https://autumnfish.cn/api/joke/list'
                    axios.get(url, {
                        params: { num }
                    }).then(res => {
                        jokes = [...jokes, ...res.jokes]
                        this.setState({ jokes })
                    }, err => {
                        console.log(err)
                    })
                }
                render() {
                    const { num, jokes } = this.state
                    if (jokes.length <= 0) {
                        return <h2>加载中,请稍后...</h2>
                    } else {
                        return (
                            <div>
                                <button onClick={this.getJokes}>获取笑话+10</button>
                                {jokes.map((item, index) => <li key={index}>{index+1+"."+item}</li>)}
                            </div>
                        )
                    }
                }
            }
    
            ReactDOM.render(<App />, document.getElementById('app'))
        </script>

    点击一次按钮,就请求10条数据,追加显示在页面上。

    8.Fragments

    React 中的一个常见模式是一个组件返回多个元素。Fragments 允许你将子列表分组,而无需向 DOM 添加额外节点。

    8.1不使用Fragments的案例

    class Table extends React.Component {
      render() {
        return (
          <table>
            <tr>
              <Columns />
            </tr>
          </table>
        );
      }
    }
    class Columns extends React.Component {
      render() {
        return (
          <div>
            <td>Hello</td>
            <td>World</td>
          </div>
        );
      }
    }
    ReactDOM.render(<Table />, document.getElementById("app"))

    这样页面渲染的table格式如下,很明显在tr到td的标签时中间加入了div标签,原因是在Columns组件中定义了父组件时包裹了div。如果不需要插入这个div标签,就可以使用Fragments

     8.2使用Fragments案例

    class Table extends React.Component {
      render() {
        return (
          <table>
            <tr>
              <Columns />
            </tr>
          </table>
        );
      }
    }
    class Columns extends React.Component {
      render() {
        return (
          <React.Fragment>
            <td>Hello</td>
            <td>World</td>
          </React.Fragment>
        );
      }
    }
    ReactDOM.render(<Table />, document.getElementById("app"))

    此案例中,使用<React.Fragment>替换了div标签,它就不会额外的插入不需要的标签。页面渲染的table格式如下

    8.3Fragment扩展

     <React.Fragment>还有一种短语法,直接写两个括号即可,如下:

    class Columns extends React.Component {
      render() {
        return (
          <>
            <td>Hello</td>
            <td>World</td>
          </>
        );
      }
    }

    如果将一个集合映射到一个 Fragments 数组,那么Fragment需要带key,就把key赋值给它即可

    function ItemList(props) {
      return (
        <dl>
          {props.items.map(item => (
            <React.Fragment key={item.id}>
              <dt>{item.term}</dt>
              <dd>{item.description}</dd>
            </React.Fragment>
          ))}
        </dl>
      );
    }

    ..

    就是这么简单,你学废了吗?感觉有用的话,给笔者点个赞吧 !
  • 相关阅读:
    07-图5 Saving James Bond
    07-图4 哈利·波特的考试(25 分)多源最短路,邻接矩阵
    最短路径问题
    最小生成树
    06-图3 六度空间(30 分)
    06-图2 Saving James Bond
    06-图1 列出连通集(25 分)邻接矩阵

    05-树9 Huffman Codes(30 分)
    集合及运算
  • 原文地址:https://www.cnblogs.com/zys2019/p/13596195.html
Copyright © 2020-2023  润新知