react基础02-非受控组件和受控组件、生命周期

非受控组件和受控组件

  非受控组件

      class Login extends React.Component {
        render() {
          return (
            <form onSubmit={this.onSubmit}>
              用户名:
              <input
                ref={(ele) => (this.username = ele)}
                type="text"
                name="username"
              />
              <br />
              密码:
              <input
                ref={(ele) => (this.password = ele)}
                type="password"
                name="password"
              />
              <br />
              <button>登录</button>
            </form>
          )
        }
        onSubmit = (e) => {
          e.preventDefault()
          const { username, password } = this
          console.log(`用户名:${username.value},密码:${password.value}`)
        }
      }
      ReactDOM.render(<Login />, document.querySelector('#test'))

  受控组件

      class Login extends React.Component {
        state = { username: '', password: '' }
        render() {
          return (
            <form onSubmit={this.onSubmit}>
              用户名:
              <input
                onChange={(e) => this.setState({ username: e.target.value })}
                type="text"
                name="username"
              />
              <br />
              密码:
              <input
                onInput={(e) => this.setState({ password: e.target.value })}
                type="password"
                name="password"
              />
              <br />
              <button>登录</button>
            </form>
          )
        }
        onSubmit = (e) => {
          e.preventDefault()
          const { username, password } = this.state
          console.log(`用户名:${username},密码:${password}`)
        }
      }
      ReactDOM.render(<Login />, document.querySelector('#test'))

  如果表单内有多个值,this.setState要写好多遍,将this.setState抽到函数中:(高阶函数和柯里化的写法)

      class Login extends React.Component {
        // #region
        /*
          高阶函数:如果一个函数符合下面2个规范中的任何一个,该函数就是高阶函数
            若A函数,接收的参数是一个函数
            若A函数,调用的函数返回值是一个函数
          常见的高阶函数:
            new Promise(()=>{})、setTimeout(()=>{},100)、arr.map(()=>{})

          函数的柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数形式
        
        */
        // #endregion
        state = { username: '', password: '' }
        render() {
          return (
            <form onSubmit={this.onSubmit}>
              用户名:
              <input
                onChange={this.saveFormData('username')}
                type="text"
                name="username"
              />
              <br />
              密码:
              <input
                onChange={this.saveFormData('password')}
                type="password"
                name="password"
              />
              <br />
              <button>登录</button>
            </form>
          )
        }
        // 函数的柯里化写法
        saveFormData = (dataType) => {
          // 内部函数作为saveFormData的返回值,成为change事件的回调【事件的回调必须是一个函数,要不然还是回调么?】
          return (event) => {this.setState({ [dataType]: event.target.value })}
        }
        onSubmit = (e) => {
          e.preventDefault()
          const { username, password } = this.state
          console.log(`用户名:${username},密码:${password}`)
        }
      }
      ReactDOM.render(<Login />, document.querySelector('#test'))

  不使用柯里化,还可以写成:(都是利用闭包)

      class Login extends React.Component {
        state = { username: '', password: '' }
        render() {
          return (
            <form onSubmit={this.onSubmit}>
              用户名:
              <input
                // change事件触发时执行回调函数,回调函数内调用saveFormData方法,将key和value传入  【如果直接写this.saveFormData('username', event) 这是将函数的返回值(undefined)当成是回调函数给change事件用,这能走得通才怪】
                onChange={(event) => this.saveFormData('username', event)}
                type="text"
                name="username"
              />
              <br />
              密码:
              <input
                onChange={(event) => this.saveFormData('password', event)}
                type="password"
                name="password"
              />
              <br />
              <button>登录</button>
            </form>
          )
        }
        saveFormData = (dataType, event) => {
          this.setState({ [dataType]: event.target.value })
        }
        onSubmit = (e) => {
          e.preventDefault()
          const { username, password } = this.state
          console.log(`用户名:${username},密码:${password}`)
        }
      }
      ReactDOM.render(<Login />, document.querySelector('#test'))

  还可以利用bind:

      class Login extends React.Component {
        state = { username: '', password: '' }
        render() {
          return (
            <form onSubmit={this.onSubmit}>
              用户名:
              <input
                // bind:当事件被触发时调用saveFormData
                onChange={this.saveFormData.bind(this, 'username')}
                type="text"
                name="username"
              />
              <br />
              密码:
              <input
                onChange={this.saveFormData.bind(this, 'password')}
                type="password"
                name="password"
              />
              <br />
              <button>登录</button>
            </form>
          )
        }
        saveFormData = (dataType, event) => {
          this.setState({ [dataType]: event.target.value })
        }
        onSubmit = (e) => {
          e.preventDefault()
          const { username, password } = this.state
          console.log(`用户名:${username},密码:${password}`)
        }
      }
      ReactDOM.render(<Login />, document.querySelector('#test'))

 

生命周期(16.x)

  

      /*
        初始化(ReactDOM.render()):constructor componentWillMount render componentDidMount
        状态更新(this.setState()):shouldComponentUpdate componentWillUpdate render componentDidUpdate
        强制更新(this.forceUpdate()):绕过shouldComponentUpdate,执行componentWillUpdate render componentDidUpdate
        卸载(ReactDOM.unmountComponentAtNode()):componentWillUnmount

        常用:
          render 必须使用,用来渲染组件
          componentDidMount 一般在这里做初始化,如:开启定时器、发送ajax请求、订阅消息
          componentWillUnmount 一般在这里做首尾,如:关闭定时器、取消订阅消息
      */
      class Count extends React.Component {
        constructor(props) {
          super(props)
          console.log('init-constructor')
          this.state = { count: 0 }
        }
        // 挂载前
        componentWillMount() {
          console.log('init-componentWillMount')
        }
        // 初始化、更新
        render() {
          console.log('init/update-render')
          const { count } = this.state
          return (
            <div>
              <h2>和为:{count}</h2>
              <button onClick={() => this.setState({ count: count + 1 })}>
                点击+1
              </button>
              <button
                onClick={ReactDOM.unmountComponentAtNode.bind(
                  this,
                  document.querySelector('#test')
                )}
              >
                卸载
              </button>
              <button onClick={() => this.forceUpdate()}>强制更新</button>
            </div>
          )
        }
        // 挂载后
        componentDidMount() {
          console.log('init-componentDidMount')
        }
        // 组件是否应该被更新
        shouldComponentUpdate() {
          console.log('update-shouldComponentUpdates')
          return true
        }
        // 更新前
        componentWillUpdate() {
          console.log('update-componentWillUpdate')
        }
        // 更新后
        componentDidUpdate() {
          console.log('update-componentDidUpdate')
        }
        // 卸载前
        componentWillUnmount() {
          console.log('卸载-componentWillUnmount')
        }
      }
      ReactDOM.render(<Count />, document.querySelector('#test'))

  

  父组件更新props,触发子组件中相应的钩子函数:

      /*
        父组件更新props(父组件render)触发子组件中钩子:componentWillReceiveProps shouldComponentUpdate componentWillUpdate render componentDidUpdate
      */
      class Parent extends React.Component {
        state = { count: 0 }
        render() {
          return (
            <div>
              <h2>父组件</h2>
              <button
                onClick={() => {
                  const { count } = this.state
                  this.setState({ count: count + 1 })
                }}
              >
                点击+1
              </button>
              <Children count={this.state.count} />
            </div>
          )
        }
      }
      class Children extends React.Component {
        constructor(){
          super()
          console.log('init-constructor')
        }
        componentWillMount() {
          console.log('init-componentWillMount')
        }
        // 接收新的props时(初始化时传了props,但是不触发此钩子)
        componentWillReceiveProps(props) {
          console.log('componentWillReceiveProps', props)
        }
        // 是否更新
        shouldComponentUpdate() {
          console.log('shouldComponentUpdate')
          return true
        }
        // 更新前
        componentWillUpdate() {
          console.log('componentWillUpdate')
        }
        // 更新后
        componentDidUpdate() {
          console.log('componentDidUpdate')
        }
        render() {
          console.log('init/update-render')
          return (
            <div>
              <h2>子组件</h2>
            </div>
          )
        }
        componentDidMount() {
          console.log('init-componentDidMount')
        }
      }
      ReactDOM.render(<Parent />, document.querySelector('#test'))

  

生命周期(17.0.1)

  

  新旧钩子对比,(将要)废弃这3个钩子:(带Will的钩子除了componentWillUnmount其他都要废弃)

    componentWillMount

    componentWillReceiveProps

    componentWillUpdate

    如果要用,要加上前缀 UNSAFE_,否则会报警告。实际使用场景极少

  新增2个钩子:

    getDerivedStateFromProps:state任何时候都取决于props时使用

    getSnapshotBeforeUpdate:在旧版render和componentDidUpdate中没有钩子,新版加了这个钩子

    这2个钩子的使用场景也极少

      class Count extends React.Component {
        constructor(props) {
          super(props)
          console.log('init-constructor')
          this.state = { count: 0 }
        }
        // 初始化、更新
        render() {
          console.log('init/update-render')
          const { count } = this.state
          return (
            <div>
              <h2>和为:{count}</h2>
              <button onClick={() => this.setState({ count: count + 1 })}>
                点击+1
              </button>
              <button
                onClick={ReactDOM.unmountComponentAtNode.bind(
                  this,
                  document.querySelector('#test')
                )}
              >
                卸载
              </button>
              <button onClick={() => this.forceUpdate()}>强制更新</button>
            </div>
          )
        }
        // 挂载后
        componentDidMount() {
          console.log('init-componentDidMount')
        }
        // constructor之后,render之前调用。此方法适用于罕见的用例,即state的值在任何时候都取决于props
        static getDerivedStateFromProps(props, state) {
          console.log('新-init/update-getDerivedStateFromProps', props, state)
          return { count1: 100 } // return props 就是将props赋值给state,这将导致组件难以维护
        }
        // 组件是否应该被更新
        shouldComponentUpdate() {
          console.log('update-shouldComponentUpdates')
          return true
        }
        getSnapshotBeforeUpdate(prevProps, prevState) {
          console.log('新-update-getSnapshotBeforeUpdate', prevProps, prevState)
          return '快照'
        }
        // 更新后
        componentDidUpdate(prevProps, prevState, snapshot) {
          console.log(
            'update-componentDidUpdate',
            prevProps,
            prevState,
            snapshot // getSnapshotBeforeUpdate钩子返回的值
          )
        }
        // 卸载前
        componentWillUnmount() {
          console.log('卸载-componentWillUnmount')
        }
      }
      ReactDOM.render(<Count />, document.querySelector('#test'))

  

  

  getSnapshotBeforeUpdate 使用场景:列表在新增的同时,滚动条一直停留在上一次滚动停留的位置(抓饭直播的评论)
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      ul {
        width: 200px;
        height: 150px;
        background-color: skyblue;
        overflow-y: auto;
      }
      li {
        height: 30px;
      }
    </style>
  </head>
  <body>
    <div id="test"></div>
    <script src="./js/17.0.1/react.development.js"></script>
    <script src="./js/17.0.1/react-dom.development.js"></script>
    <script src="./js/17.0.1/babel.min.js"></script>
    <script src="./js/17.0.1/prop-types.js"></script>
    <script type="text/babel">
      class NewList extends React.Component {
        state = { list: [] }
        render() {
          return (
            <div>
              <ul ref="list">
                {this.state.list.map((item, index) => (
                  <li key={index}>{item}</li>
                ))}
              </ul>
              <button
                onClick={ReactDOM.unmountComponentAtNode.bind(
                  this,
                  document.querySelector('#test')
                )}
              >
                卸载
              </button>
            </div>
          )
        }
        componentDidMount() {
          this.timer = setInterval(() => {
            const { list } = this.state
            const data = '新增' + (list.length + 1)
            this.setState({ list: [data, ...list] })
          }, 500)
        }
        getSnapshotBeforeUpdate() {
          return this.refs.list.scrollHeight
        }
        componentDidUpdate(prevProps, prevState, height) {
          this.refs.list.scrollTop += this.refs.list.scrollHeight - height
        }
        componentWillUnmount() {
          clearInterval(this.timer)
        }
      }
      ReactDOM.render(<NewList />, document.querySelector('#test'))
    </script>
  </body>
</html>
View Code

  效果:

    

  使用shouldComponentUpdate钩子也可以达到同样的效果:

        shouldComponentUpdate() {
          this.height = this.refs.list.scrollHeight
          return true
        }
        componentDidUpdate() {
          this.refs.list.scrollTop += this.refs.list.scrollHeight - this.height
        }

 

key值的唯一性

使用index作为key的问题:

  

  如果使用index作为key,下一次更新时,index顺序被打乱,会造成key值比对的结果都为false,这就意味着,即使是相同的dom,也需要重新渲染一遍,造成性能上的浪费

      /*
        key值的作用:
          当状态中的数据发生变化时,react会根据新数据生成新的虚拟dom,随后react进行【新虚拟dom】和【旧虚拟dom】的diff比较,比较规则如下:
            ①旧虚拟dom中找到了与新虚拟dom相同的key,若虚拟dom内容没变,直接使用之前的真实dom,若虚拟dom的内容变了,随后替换掉页面中之前的真实dom
            ②旧虚拟dom中未找到与新虚拟dom相同的key,根据数据创建新的真实dom,随后渲染到页面
          
        用index作为key可能会引发的问题:
          ①若对数据进行逆序添加、逆序删除等破坏顺序的操作,会造成没有必要的真实dom更新,页面效果没有问题,但效率低
          ②如果结构中还包含输入类的dom,会产生错误的dom更新,因为虚拟dom的比对最小颗粒度是标签,输入类的dom会被认为是上一次相同的dom
        
        key值的选择:
          1、最好用id、手机号、身份证号、学号等唯一值
          2、如果不存在对数据的逆序添加和删除等破坏顺序的操作,仅用于渲染列表,使用index作为key没有问题
      
      */

 

 

 

 

 

 

 

 

组件传值:

  父传子:

    传递:给子组件标签上绑定一个自定义属性,值为需要传递的数据

        <One username={this.state.name}></One>

    接收:在子组件render函数中通过props接收

        let { username } = this.props

  * react中如何限制传递来的数据类型和设置初始值:

    ①下载插件:npm i prop-types      从v15.5开始,React.PropTypes助手函数被弃用,使用 prop-types 库来定义 contextTypes

    ②在子组件中引入:import PropTypes from 'prop-types'

    ③对当前组件进行类型限制和默认值的设置

        // propTypes是组件上的属性,PropTypes是数据类型检测
        Two.propTypes = {
          name: PropTypes.string
        }

        Two.defaultProps = {
          name: '吴小明'
        }

  * vue中是怎样限制类型和设置初始值的:

    

  子传父:

    传递:在子组件中通过 this.props.事件函数 来进行传值

        <button onClick={this.handleAdd.bind(this)}>点击发送给父组件</button>

handleAdd() { this.props.toApp('我是从two组件传来的') }

    接收:在子组件标签上绑定一个自定义属性,值为需要接收参数的函数

        <Two toApp={this.handle2.bind(this)}></Two>


        handle2(value) {
          this.setState({
            towValue: value
          })
        }    

   非父子:

    1、通过onserver传值

      ①定义observer.js

const eventList = {}

const $on = function(eventName, callback) {
  if (!eventList[eventName]) {
    eventList[eventName] = []
  }

  eventList[eventName].push(callback)
}

const $emit = function(eventName, params) {
  if (eventList[eventName]) {
    var arr = eventList[eventName]
    arr.forEach((cb) => {
      cb(params)
    })
  }
}

const $off = function(eventName, callback) {
  if (eventList[eventName]) {
    if (callback) {
      var index = eventList[eventName].indexOf(callback)
      eventList[eventName].splice(index, 1)
    } else {
      eventList[eventName].length = 0
    }
  }
}

export default {
  $on,
  $emit,
  $off
}
View Code

      ②在需要传递的组件中引入observer.js

        import Observer from '../observer'

      通过Observer.$emit()传值:

        <button onClick={this.handleClick.bind(this,'传个值给Two组件')}>传个值给Two组件</button>
         handleClick(value){
           Observer.$emit('abcd',value)
         }

      ③在需要接收的组件中引入observer.js

        import Observer from '../observer'

      通过Observer.$on()接收值

            constructor() {
              super()
              this.state = {
                value: ''
              }
              Observer.$on('abcd', (value) => {
                this.setState({
                  value
                })
              })
            }

    2、通过context传值

      vue中:provide/inject

      react中:通过context创建一个生产者,再创建一个消费者供组件使用。其中生产者是父级,消费者是子级。

      实践step:

        ①创建createContext.js文件

          import React, { createContext } from 'react'

          export let { Provider, Consumer } = createContext() // Provider生产者,Consumer消费者

        ②在父级中引入Provider并将当前根节点包裹,Provider标签中value属性中是一个对象,用于传值

             import { Provider } from './createContext'

                  render() {
                    return (
                      // Provider包裹所有的子级
                      <Provider
                        value={{
                          name: '孙艺珍',
                          age: 18
                        }}
                      >
                        <div className="app">
                          <One></One>
                        </div>
                      </Provider>
                    )
                  }            

        ③在自己中引入Consumer并将当前根节点包裹,Consumer中是一个函数返回一个jsx

           import { Consumer } from '../createContext'

                  render() {
                    return (
                      // Consumer包裹的组件接收Provider传来的值,Consumer中是一个函数返回一个jsx语法
                      <Consumer>
                        {(props) => {
                          let { name, age } = props
                          return (
                            <div className="Two">
                              <h1>Two组件</h1>
                              接收到来自Provider传来的name为:{name},age为:{age}
                              <Three></Three>
                            </div>
                          )
                        }}
                      </Consumer>
                    )
                  }

      利用高阶组件对Consumer进行二次封装:

        ①src下创建connect/createContext.js

          import React, { createContext } from 'react'

          export let { Provider, Consumer } = createContext()

        ②src下创建高阶组件:hoc/connect.js 用于封装Consumer

                import React from 'react'
                import { Consumer } from '../connect/createContext'

                export const connect = (WrapperComponent) => {
                  return class extends React.Component {
                    render() {
                      return (
                        <Consumer>
                          {(props) => {
                            return <WrapperComponent {...props}></WrapperComponent>
                          }}
                        </Consumer>
                      )
                    }
                  }
                }

        ③在父组件中通过Provider传值

                import React, { Component } from 'react'
                import Two from './two'
                import { Provider } from '../connect/createContext'

                class One extends Component {
                  render() {
                    return (
                      <Provider value={{ name: '孙艺珍', sex: '女' }}>
                        <div className="One">
                          <h1>One组件</h1>
                          <Two></Two>
                        </div>
                      </Provider>
                    )
                  }
                }

                export default One

        如果用原来的Consumer接收:

                import React, { Component } from 'react'
                import Three from './three'
                import { Consumer } from '../connect/createContext'

                class Two extends Component {
                  render() {
                    return (
                      <Consumer>
                        {(props) => {
                          let { name, sex } = props
                          return (
                            <div className="Two">
                              <h1>Two组件</h1>
                              姓名:{name},性别:{sex}
                              <Three></Three>
                            </div>
                          )
                        }}
                      </Consumer>
                    )
                  }
                }

                export default Two

        ④用封装好的Consumer接收:

                import React, { Component } from 'react'
                import { connect } from '../hoc/connect'

                class Three extends Component {
                  render() {
                    let { name, sex } = this.props
                    return (
                      <div className="Three">
                        <h1>Three组件</h1>
                        姓名:{name},性别:{sex}
                      </div>
                    )
                  }
                }

                export default connect(Three)

        

    3、redux:公共状态管理

 

组件分类:

  1、类组件 - class App extends React.Component {render (){}}

  2、函数组件 - function fn (){return (<div>我是一个函数组件</div>)}

  3、ui组件

  4、容器组件

  5、高阶组件

  6、受控组件 - input加上value属性和onChange事件后变为受控组件

  7、非受控组件 - input加上defaultValue依旧可以输入内容,此时为非受控组件

 

  react中函数组件和类组件的区别:

    函数组件:相比较类组件来说比较轻便、速度较快(16.8中引入hooks来解决函数组件的这个问题)

    类组件:有属于自己的生命周期,可以在指定的时间做指定的事,可以存储属于自己的状态

  高阶组件:

    高阶组件是一个函数,它接收一个组件返回一个相对增强性的组件,简称HOC

 

react中的插槽:

  只需在子组件中通过 this.props.children 进行嵌套的内容。

  1、子组件标签中的内容默认是不显示的:

    import React from 'react'
    import Header from './Header'
    class App extends React.Component {
      render() {
        return (
          <div className="app">
            <Header>
              <h2>标题</h2>
            </Header>
          </div>
        )
      }
    }

    export default App

  2、子组件中通过 this.props.children 接收

    import React from 'react'
    import './index.css'

    class Header extends React.Component {
      render() {
        return <div className="header">{this.props.children}</div>
      }
    }

    export default Header

 

生命周期:

  1、constructor:

    1、当前生命周期是组件在初始化的时候执行的,在constructor中必须要写super()否则this的指向会发生错误

    2、可以在当前生命周期中存放当前组件所需的一些状态,这些状态必须要放到this.state中

    3、在当前生命周期中访问不到this.props,如果要访问this.props必须要在constructor中传入props

        constructor(props) {
          super(props)
          this.state = {
            msg: '孙艺珍'
          }
          console.log('constructor', props,this.props) // 在super中传入props才可以用this.props接收到数据
        }

  2、componentWillMount:

    1、当前生命周期是组件挂载前。此时数据和模板还未结合,因此可以在当前生命周期中做数据最后的更改

    2、当前生命周期中可以接收到外部的数据,可以访问到this.props

    3、在v17.0中被废除,使用时页面会报警告

    

  3、render:(多次执行)

    1、当前生命周期是一个渲染函数,是数据和模板相结合的一个函数。当前生命周期在执行的时候会将渲染好的模板在缓存中存储一份,这就是diff算法比较(diff算法:新旧两个虚拟DOM的对比)

    2、当前生命周期会多次执行,当this.setState()或者this.props发生改变的时候就会执行

    3、可以通过控制shouldComponentUpdate来减少render函数渲染的次数来优化性能

  4、componentDidMount:

    1、当前生命周期是数据和模板已经结合完毕并且挂载到页面上,因此我们可以在当前生命周期中获取到真实的DOM结构

    2、通常会在当前生命周期中进行前后端数据的交互和方法的实例化(swiper)

    react中如何访问到DOM节点:

      第一种:<h2 ref='h2'></h2>

          this.refs.h2

      第二种:<h2 ref={(h2)=>{this.h2=h2}}></h2>

          this.h2

        render() {
          return (
            <div>
              <h1>One组件</h1>
              <h2 ref="h2">h2标签</h2>
              <h3 ref={(h3) => (this.h3 = h3)}>h3标签</h3>
            </div>
          )
        }
        componentDidMount() {
          console.log('挂载后', this.refs.h2,this.h3) // <h2>h2标签</h2> <h3>h3标签</h3>
        }

  5、componentWillReceiveProps:(多次执行)

    1、当props的数据发生改变的时候会执行当前生命周期,在当前生命周期函数中有个参数,该参数是新的props

    2、当前生命周期在v17.x的版本中被废除

  6、shouldComponentUpdate:(多次执行)

    1、当前生命周期书写的时候必须return一个布尔值,当值为true时继续执行下面的生命周期;如果为false不执行下面的生命周期

    2、当前生命周期中有2个参数,一个是新的props,一个是新的state,可以根据新的props/state与旧的props/state比较减少render函数的渲染次数

    3、当前生命周期决定render函数是否渲染,而不是决定数据是否更新

        shouldComponentUpdate(newProps, newState) {
          console.log('决定数据是否更新', newProps, newState)
          if (this.state.msg === newState.msg) {
            return false
          } else {
            return true
          }
        }

  7、componentWillUpdate:(多次执行)

    1、当前生命周期在数据更新时执行,有2个参数,一个是新的props,一个是新的state

    2、可以在当前生命周期中对数据进行最后的更改

    注意:

      1、尽量不要在当前生命周期中调用this.setState(),死循环

      2、当前生命周期在v17.0中被废除

  8、componentDidUpdate:(多次执行)

    1、当前生命周期在数据更新完后执行,可以在这里获取到数据更新后最新的DOM结构(一定要加边界条件)

    2、当前生命周期中有2个参数,一个是旧的props,一个是旧的state

  9、componentWillUnmount:

    当前生命周期在组件被卸载时执行,可以在当前生命周期做性能的优化:事件的解绑、定时器的移除……

 

react中如何强制更新数据:

  this.forceUpdate()

  注:vue中通过this.$forceUpdate()

 

常见的生命周期面试题:

  1、react中哪些生命周期会执行一次,哪些会执行多次

    执行一次:

      constructor

      componentWillMount

      componentDidMount

      componentWillUnmount

    执行多次:

      componentWillReceiveProps

      shouldComponentUpdate

      componentWillUpdate

      render

 

      componentDidUpdate

  2、react中第一次执行的生命周期有哪些

    constructor

    componentWillMount

    render

    componentDidMount

  3、render什么时候被触发

    当this.props或this.setState()发生改变的时候触发

  4、谈谈对shouldComponentUpdate的理解

  5、当this.props或this.setState()执行的时候会触发哪些生命周期

    this.props:

      componentWillReceiveProps

      shouldComponentUpdate

      componentWillUpdate

      render

      componentDidUpdate

    this.setState():

      shouldComponentUpdate

      componentWillUpdate

      render

      componentDidUpdate

 

css in js:styled-components  将css组件化

  安装插件:npm install styled-components

  新建styled.js:

    import styled, { keyframes } from 'styled-components'
    import logo from '../../logo.png' // 图片的引入

    // 定义动画
    const move = keyframes`
      0%{
        transform:rotate(0deg);
      }
      100%{
        transform:rotate(360deg);
      }
    `
    export const HeaderContainer = styled.div`
      width: 100%;
      height: 1rem;
      background-color: ${(props) => props.color}; /* 可以传参 */
      color: #fff;
      display: flex;
      justify-content: center;
      align-items: center;
      /* 像sass和less一样嵌套 */
      button {
        background-color: yellow;
        border: 0;
        animation: ${move} 3s 1s;
      }
      button.a {
        background-color: #c33;
      }
    `
    // 可以接收父组件传来的值渲染
    export const SerachInput = styled.input.attrs((props) => ({
      type: props.type,
      value: props.value
    }))`
      width: 60%;
      height: 0.5rem;
      border: 0;
      border-bottom: 1px solid #ccc;
      background-image: url(${logo}); /* 图片的使用 */
      background-repeat: no-repeat;
      background-size: 100% 100%;
    `
    export const MyButton = styled.button`
      width: 100px;
      height: 40px;
      text-align: center;
      line-height: 40px;
      color: black;
      background-color: yellow;
      border: 0;
      animation: ${move} 3s 1s;
    `
    // 继承
    export const ChildrenButton = styled(MyButton)`
      background-color: green;
    `

  index.jsx中引入和使用:

    import React, { Component } from 'react'
    import {
      HeaderContainer,
      SerachInput,
      MyButton,
      ChildrenButton
    } from './styled'

    class Header extends Component {
      constructor() {
        super()
        this.state = {
          inputVal: '请输入'
        }
      }
      render() {
        return (
          <div>
            <HeaderContainer color="deeppink">
              猫眼电影
              <SerachInput
                type="text"
                value={this.state.inputVal}
                onChange={this.onChange.bind(this)}
              ></SerachInput>
              {/* <MyButton>按钮</MyButton>
              <ChildrenButton>子按钮</ChildrenButton> */}
              <button>按钮</button>
              <button className="a">按钮</button>
            </HeaderContainer>
          </div>
        )
      }
      onChange() {}
    }

    export default Header

 

ReactDOM.unmountComponentAtNode
posted @ 2021-01-12 15:53  吴小明-  阅读(128)  评论(0编辑  收藏  举报