react基本语法总结?

x33g5p2x  于2022-05-11 转载在 其他  
字(20.5k)|赞(0)|评价(0)|浏览(430)

1、js和jsx有什么区别,为什么要使用jsx

// ①jsx的使用
 <script type="text/babel">
    const VDOM = <h1 id='title'>hell,react</h1>
    ReactDOM.render(VDOM, document.getElementById('test'))
  </script>
②js的使用
  <script type="text/javascript">
    const VDOM = React.createElement('h1', {id:'title'}, 'hello react')
    ReactDOM.render(VDOM, document.getElementById('test'))
  </script>
使用js而不使用jsx的原因是:程序员写jsx会使代码更加简洁,而使用js来创建虚拟DOM,则会显得更加繁琐。虽然在jsx在执行bable转化的使用,仍然转化成js。

2、react虚拟dom和真实dom的区别?

<script type="text/babel">
    const VDOM = <h1>hello,react</h1>
    const TDOM = document.getElementById('test')
    ReactDOM.render(VDOM, document.getElementById('test'))
    console.log('虚拟DOM:',VDOM)
    console.log('真实DOM:',TDOM)
    debugger;
  </script>
1、虚拟dom其实只是一个对象
2、虚拟dom比较“轻”, 真实dom比较"重",原因是react中的虚拟dom只是将抽离出一些可以用得到的属性,但是在真实dom中会加载全部属性。
3、虚拟dom存放在内存中,等到使用完成后,就会转化成真实dom,呈现在真实的页面上。

3、什么是XML,为什么会将XML换成json

<students>
	<name>TOM</name>
	<age>20</age>
</students>
缺点:数据保存少,需要消耗的空间多,所有才有了JOSN数据类型

4、JSX语法

1、定义虚拟dom的时候,不需要写引号
2、标签中混入js表达式时要使用{}
3、样式的类名指定不要使用class,而是使用className
4、内联样式,需要使用style={{color:value}}的形式去写
5、只有一个根标签
6、标签必须闭合
7、标签首字母
	(1)若小写字母开头,则将该标签转为html中同名元素,若html中无该标签对应的同名元素,则报错
	(2)若大写字母开头,react就去渲染对应的组件,若组件没有定义,则报错、

5、在jsx中使用的是js表达式,注意和js语句之间的区别

<script type="text/babel">
  const data = ['vue','react', 'angular']
    const VDOM = (
      <ul>
        {
          // 使用大括号中间放的是js表达式,注意和js语句之间的区别
          data.map((item,index)=> {
            return <li key={index}>{item}</li>
          })
        }  
      </ul>
    )
    ReactDOM.render(VDOM, document.getElementById('test'))
  </script>
js表达式有:
1、a
2、a + b
3、arr.map()
4、function test()
5、函数调用 demo(1)

js语句有:
1、if语句
2、for循环语句
3、switch语句

5、函数式组件

1、基本实现
  <script type="text/babel">
     //创建函数式组件
    function MyComponent () {
      return <h2>这里是函数式组件</h2>
    }
	//执行render渲染操作
    ReactDOM.render(<MyComponent/>, document.getElementById('test'))
  </script>

执行函数式组件的步骤流程:
1、先找到MyComponent函数式组件
2、然后将返回的虚拟dom渲染成真实的dom
3、最后展示到页面上

6、类组件

<script type="text/babel">
    class MyComponent extends React.Component {
      render() {
        console.log(this)
        return <h1>这里是类组件的实现</h1> 
      }
    }
    
    ReactDOM.render(<MyComponent/>, document.getElementById('test'))
  </script>
注意事项:
1、需要继承React.Component。
2、可以没有构造函数。

类式组件的执行流程

1、React解析先找到MyComponent组件
2、发现该组件是通过类进行定义的,首先通过new一个实例对象,然后调用实例对象中的render方法。
3、将render返回的虚拟dom转化成真是的dom,随后展示到页面上。

7、设置点击事件

1、ES6中的事件默认开启局部严格模式
2、 babel在进行转化js文件的时候,会避免this指向window,而是让this的值赋值给undefined。
<script type="text/babel">
    class MyComponent extends React.Component {
      constructor(props) {
        super(props)
        this.state = {
          isHot : false
        }
        this.changeWeather = this.changeWeather.bind(this)
      }
      render() {
        const {isHot} = this.state
        return <h1 onClick={this.changeWeather}>今天天气真{isHot ? '炎热' : '寒冷'}</h1>
      }

      changeWeather() { 
        this.setState({
          isHot:!this.state.isHot
        })
      }
    }

    ReactDOM.render(<MyComponent/>,document.getElementById('test'))
  </script>
//注意事项:
1、在调用函数的时候注意this的指向,可以使用bind
2、更改state中的值的时候,必须使用setState函数来进行更改,传入的参数是对象,是抽取更改不是全部覆盖。
3、在执行过程中,构造函数执行1次,render函数执行1 + n(n为修改的次数),changeWeather函数执行n次,n为点击的次数。

8、apply和call以及bind之间的区别?
1、bind方法

1、bind第一个参数为this指向的对象,第二个参数到第n个参数均为传入的值
2、bind的传入参数之后,需要再次进行调用
3、每次执行bind方法时都会新建一个函数
4、自己实现简单的bind方法
5、如果直接在bind后面只有一个括号,不能实现函数调用。
  Function.prototype.my_bind = function (context) {
    let self = this
    return function () {
      return self.apply(context, arguments)
    }
  }

  function add (c, d) {
    return this.x + c + d
  }

 console.log(add.bind({x:100}, 10, 1)())

二、call方法

1、第一个参数是this指向的对象,第二个参数到第n个参数是需要传入的值。
2、方法.call()可以实现函数调用。

三、apply方法

1、 第一个参数是this指向的对象,第二个参数是一个数组,也可以是arguments
2、方法.apply()也可以实现函数调用

9、触发事件的简写形式

<script type="text/babel">
    class Weather extends React.Component {
      state = {                                                ----------------------------------①
        isHot:true
      }
      render() {
        const {isHot} = this.state
        return <h1 onClick={this.changeWeather}>今天天气是{isHot ? '炎热' : '寒冷'}</h1>
      }
      changeWeather = () => {                                        --------------------------②
        this.setState({
          isHot:!this.state.isHot
        })
      }
    }
    ReactDOM.render(<Weather />, document.getElementById('test'))
  </script>
1、如果某一些属性不需要外部来传入,可以像①处这样写
2、可以将方法也不放在原型对象上,直接放在该类中,这里需要使用箭头函数,类似于图中的② 
3、注意事件的书写格式上,需要将onclick写成onClick

11、类组件中的props属性

<script type="text/babel">
    class Person extends React.Component {
      render() {
        const {name,age,sex} = this.props
        console.log(this)
        return (
          <ul>
            <li>姓名:{name}</li>  
            <li>性别:{sex}</li>  
            <li>年龄:{age}</li>  
          </ul>
        )
      }
    }

    ReactDOM.render(<Person name="董礼" age="20" sex="男" />, document.getElementById('test'))
  </script>
1、在每一个实例组件对象中都会存在一个属性props。
2、可以直接在组件进行传值

11、对象解构

<script>
    let p1 = {name:'张三',age:20, sex:'男'}
    let p2 = {...p1}
    p1.name = '李四'
    console.log(p1)  //{name:'李四',age:20, sex:'男'}
    console.log(p2)  //{name:'张三',age:20, sex:'男'}
  </script>
对象如果想要结构必须使用{...对象名},这样得到的就是另一个对象。

可以在给类组件传入参数时进行解构处理

原因:因为该文件是react和babel一起结合使用的,只能在组件标签中使用对象的解构。
<script type="text/babel">
    class Person extends React.Component {
      render () {
        const {name, age, sex} = this.props
        return (
          <ul>
            <li>姓名:{name}</li>
            <li>年龄:{age}</li>
            <li>性别:{sex}</li>  
          </ul>
        )
      } 
    }

    let p1 = {name:"张三", age:'20', sex: "男"}
    ReactDOM.render(<Person {...p1}/>, document.getElementById('test'))
  </script>

12、
设置传入props的数据类型以及是否被需要,并且可以设置props的属性默认值。

<script type="text/babel">
    class Person extends React.Component {
      render() {
        const { name, age, sex ,speak} = this.props
        console.log(speak)
        return (
          <ul>
            <li>姓名:{name}</li>
            <li>年龄:{age + 1}</li>
            <li>性别:{sex}</li>
          </ul>
        )
      }
    }
    // 设置类型
    Person.propTypes = {
      name:PropTypes.string.isRequired,
      age:PropTypes.number.isRequired,
      sex:PropTypes.string.isRequired, 
      speak:PropTypes.func,
    }

    // 设置默认值
    Person.defaultProps = {
      name:'董沐辰',
      age:20,
      sex:'女'
    }

    const p1 = {}
    ReactDOM.render(<Person {...p1}/>, document.getElementById('test'))
    ReactDOM.render(<Person name="李四" age={20} sex="男" speak = {speak}/>, document.getElementById('test1'))

    function speak() {
      console.log('我要说话')
    }
1、这里还可以给函数类型限制,注意函数类型限制的类型必须是func,数字和字符串类型的限制必须使用小写。
2、如果需要给组件标签传入js代码,则必须使用{}来表示。

13、将该组件类中的属性设置为类的静态属性

<script type="text/babel">
    class Person extends React.Component {
      render() {
        const {name,age,sex} = this.props
        return (
          <ul>
            <li>姓名:{name}</li>
            <li>年龄:{age}</li>
            <li>性别:{sex}</li>
          </ul>
        )
      }
      static propTypes = {
        name:PropTypes.string.isRequired,
        sex:PropTypes.string,
        age:PropTypes.number
      }
      static defaultProps = {
        name:'张三',
      }
    }
    let p1 = {name:'张三',age:20, sex:'男'}
    ReactDOM.render(<Person {...p1}/>, document.getElementById('test'))

  </script>

14、类中的构造器

//组件类的构造器的作用:
  <script type="text/babel">
    class Person extends React.Component {
      constructor(props) {
        super(props)
        console.log('constructor', this.props)
      }
      render() {
        const {name,age,sex} = this.props
        return (
          <ul>
            <li>姓名:{name}</li>
            <li>年龄:{age}</li>
            <li>性别:{sex}</li>
          </ul>
        )
      }
      static propTypes = {
        name:PropTypes.string.isRequired,
        sex:PropTypes.string,
        age:PropTypes.number
      }
      static defaultProps = {
        name:'张三',
      }
    }
    let p1 = {name:'张三',age:20, sex:'男'}
    ReactDOM.render(<Person {...p1}/>, document.getElementById('test'))

  </script>
官网上的constructor的两种用法:
1、通常,在react中,构造函数仅用于以下两种情况。
通过给this.state赋值对象类初始化内部的state。
为事件处理函数绑定实例。
第一个我们使用属性实现,第二个我们使用箭头函数实现

其实构造函数可以不进行使用,如果我们想要在构造函数中使用this.props,则必须传入props以及使用super(props)进行传值、

15、函数式组件

<script type="text/babel">
    function Person(props) {
      const {name, age, sex} = props
      return (
        <ul>
          <li>姓名:{name}</li>
          <li>年龄:{age}</li>
          <li>性别:{sex}</li>
        </ul>
      )
    }
    Person.propTypes = {
      name:PropTypes.string.isRequired,
      age:PropTypes.number,
      sex:PropTypes.string
    }
    Person.defaultProps = {
      name:'李四',
      age:300,
      sex:'女'
    }
    ReactDOM.render(<Person/>, document.getElementById('test'))
  </script>
在函数是组件中,需要注意的事项:
1、目前函数式组件没有this,但是只能得到props属性。
2、函数式组件中没有state和refs。
3、函数式组件可以通过给组件传属性,最终传入props中,并且可以给属性设置类型限制和设置默认值。

16、refs和ref的使用

<script type="text/babel">
    class Demo extends React.Component {
      set = () => {
        const {input1} = this.refs
        alert(input1.value)
      }
      bule= () => {
        const {input2} = this.refs
        alert(input2.value)
      }
      render() {
        return (
          <div>
            <input ref="input1" type="text" placeholder="点击"/>&nbsp;
            <button onClick={this.set}>点击我触发左侧事件</button>&nbsp;
            <input ref="input2" onBlur={this.bule} type="text" placeholder="失去焦点"/>
          </div>
        )
      } 
    }

    ReactDOM.render(<Demo/>, document.getElementById('test'))
  </script>
1、可以通过ref来获取该标签。
2、refs中包含了这个类组件对象中的全部的ref。

17、ref使用回调函数的形式,ref=字符串的形式效率太低。

<script type="text/babel">
    class Person extends React.Component {
      set = () => {
        const {input1} = this
        alert(input1.value)
      }
      blur = () => {
        const {input2} = this
        alert(input2.value)
      }
      render() {
        return (
          <div>
            <input ref={(currentNode)=> {this.input1 = currentNode}} type="text" placeholder='点击'/>  
            <button onClick={this.set}>点击</button>
            <input ref={(currentNode) => {this.input2 = currentNode}} type="text" onBlur ={this.blur} placeholder='失去焦点'/>
          </div>
        )
      }
    }

    ReactDOM.render(<Person/>, document.getElementById('test'))
  </script>
1、如果ref=回调函数,比如使用{}把其括起来。
2、并且使用箭头函数的形式,因为箭头函数中的this指向的是这个实例对象本身。
3、ref传入的参数是该节点的对象,使用this.input = currentNode ,是向这个实例对象上面赋值.
4、最后在触发的方法中使用解构对this进行解构即可。
5、这里中的ref是react自动帮我们调用的函数。

18、ref设置内联函数和绑定函数的区别
1、内联函数

当页面发生改变的时候,页面会重新渲染,内联函数会执行两次,第一次传入的currentNode的值是null,第二次传入的是才是这个节点。
<script type="text/babel">
    class Demo extends React.Component {
      state = {
        isHot:true
      }
      set = ()=> {
        const {input1} = this
        alert(input1.value)
      }
      changeWeather=() => {
        this.setState({
          isHot: !this.state.isHot
        })
      }
      render () {
        const {isHot} = this.state
        return (
          <div>
            <h1>天气是{isHot ? '炎热' : '寒冷'}</h1>
            <input type="text" ref={(currentNode)=> {this.input1 = currentNode;console.log('@@',currentNode)}}/>
            <button onClick={this.set}>点击展示数据</button>
            <button onClick={this.changeWeather}>点击修改天气</button>
          </div>
        )
      }
    }

    ReactDOM.render(<Demo/>, document.getElementById('test'))
  </script>

2、绑定函数 如果使用绑定函数的时候,当页面发生变化的时候,只会执行一次,并且传给currentNode的值,就是该节点。

<script type="text/babel">
    class Demo extends React.Component {
      state = {
        isHot:true
      }
      set = ()=> {
        const {input1} = this
        alert(input1.value)
      }
      changeWeather=() => {
        this.setState({
          isHot: !this.state.isHot
        })
      }
      sss = (currentNode) => {
        this.input1 = currentNode
        console.log('@@', currentNode)
      }
      render () {
        const {isHot} = this.state
        return (
          <div>
            <h1>天气是{isHot ? '炎热' : '寒冷'}</h1>
            <input type="text" ref={this.sss}/>
            <button onClick={this.set}>点击展示数据</button>
            <button onClick={this.changeWeather}>点击修改天气</button>
          </div>
        )
      }
    }

    ReactDOM.render(<Demo/>, document.getElementById('test'))
  </script>

两者中第一个在开发中使用的频率高
第三种实现ref的方式

<script type="text/babel">
    class Demo extends React.Component {
      myRef = React.createRef()
      myRef1 = React.createRef()
      set = ()=> { 
        alert(this.myRef.current.value)
      }
      blur = () => {
        alert(this.myRef1.current.value)
      }
      render() {
        return (
          <div>
            <input ref={this.myRef} type="text" placeholder='点击'/>  
            <button onClick={this.set}>点击</button>
            <input onBlur={this.blur} ref={this.myRef1} type="text" placeholder='失去焦点'/>
          </div>
        )
      }
    }

    ReactDOM.render(<Demo/>, document.getElementById('test'))
  </script>
1、这里使用React.createRef()这个API来进行创建。
2、在类对象实例上进行设置。
3、每一个React.createRef()只能使用一次。

19、react中的事件处理

1、注意事件的大小写,例如点击事件必须写成onClick
原因:因为需要考虑到事件的兼容性问题,并且和原来的事件区分开。

2、React中事件是通过事件委托的方式处理的(将事件委托给最外层的元素)使用的原理是事件冒泡。
为了高效

3、可以通过event.target得到发生事件的DOM元素的对象,原因是不能过度的使用ref。
<script type="text/babel">
    class Demo extends React.Component {
      blur = (event) =>{
        console.log(event.target.value)
      }
      render() {
        return (
          <div>
            <input onBlur= {this.blur} type="text"/>
          </div>
        )
      }
    }

    ReactDOM.render(<Demo/>, document.getElementById('test'))
  </script>

20、事件委托

1、事件委托利用的原理是事件冒泡。
2、事件委托减少操作dom的次数,可以极大解决性能的问题。
3、事件委托可以减少设置事件,减少内存占有。

21、非受控组件

<script type="text/babel">
    class Form extends React.Component {
      submitForm = (event) => {
        event.preventDefault()  
        const {username, password} = this
        alert(`提交的用户姓名为:${username.value},用户密码为:${password.value}`)
      }
      render() {
        return (
          <form action="https://www.baidu.com" onSubmit ={this.submitForm}>
          用户名:<input type="text" name="username" ref={c=> this.username = c}/>  
          密码:<input type="password" name="password" ref={c=> this.password = c}/>
          <button>点击提交</button>
          </form>
        )
      }
    }
    ReactDOM.render(<Form/>, document.getElementById('test'))
  </script>
1、当在form表单中提交的时候,触发的事件是onSubmit事件。
2、event.preventDefault()表示阻止默认事件。
3、非受控组件就是什么时候需要用到ref表示的标签什么时候取出来即可。

22、受控组件

<script type="text/babel">
    class Form extends React.Component {
      state = {
        username:'',
        password: ''
      }
      nameChange = (event) => {
        this.setState({
          username:event.target.value
        })
      }
      passChange = (event) => {
        this.setState({
          password:event.target.value
        })
      }
      render() {
        return (
          <form action="">
            姓名:<input type="text" onChange={this.nameChange}/>  
            密码:<input type="password" onChange={this.passChange}/>
          </form>
        )
      }
    }

    ReactDOM.render(<Form/>, document.getElementById('test'))
  </script>

受控组件和非受控组件的区别

1、受控组件,随时都能获取到组件中对应的值,类似于vue中的数据的双向绑定。
2、非受控组件,只有需要的时候才能获取到组件中对应的值,例如当提交表单时,才会获取表单中的对应的input框中的值。
3、而且我们在项目中最好使用受控组件。

对上面的受控组件进行化简

<script type="text/babel">

    class Form extends React.Component {
      state = {
        username:'',
        password:''
      }
      saveFormData = (data) => {
        return (event) => {
          this.setState({
            [data]:event.target.value
          })
        }
      }
      render() {
        return (
          <form action="">
          用户名:<input type="text" onChange = {this.saveFormData('username')}/>  
          密码:<input type="text" onChange = {this.saveFormData('password')}/>
          </form>
        )
      }
    }
    ReactDOM.render(<Form/>, document.getElementById('test'))
  </script>

设置saveFormData通过对其传入属性名,从而进行封装,避免代码冗余
23、高阶函数

定义:如果一个函数传入的参数是一个函数,或者返回的是一个函数,这两类满足其一,即可成该函数为高阶函数。

柯里化:

//代码如下所示即为柯里化,或者正如saveFormData这个函数就是柯里化
    function set(a) {
      return function (b) { 
        return function (c) {
          return a + b + c
        }
      }
    }

    console.log(set(1)(2)(4))

在不使用柯里化和高阶函数的前提下,重写上述代码

<script type="text/babel">

    class Form extends React.Component {
      state = {
        username: '',
        password: ''
      }

      saveFormData(dataType, event) {
        this.setState({
          [dataType]:event.target.value
        })
      }

      render() {
        return (
          <form action="">
            用户名:<input type="text" onChange = {event=>this.saveFormData('username', event)}/>    ----------------①
            密码:<input type="text" onChange = {event =>this.saveFormData('password', event)}/>    ----------------——②
          </form>
        )
      }
    }

    ReactDOM.render(<Form />, document.getElementById('test'))
  </script>

24、react生命周期

<script type="text/babel">
    class Life extends React.Component {
      state = {
        opacity: 1
      }
      remove = () => {
        // 卸载组件
        ReactDOM.unmountComponentAtNode(document.getElementById('test'))
      }

      // 组件挂载完毕
      componentDidMount() {
        console.log('组件挂载完毕')
        this.timer = setInterval(() => {
          let {opacity} = this.state
          opacity -= 0.1
          this.setState({
            opacity
          })
          if(opacity <= 0){  //这里不使用opacity == 0的原因是:因为js中小数相减存在误差
            this.setState({
              opacity:1
            })
          }
        },200)
      }

      // 在卸载组件之前
      componentWillUnmount() {
        console.log('组件卸载之前')
        clearInterval(this.timer)
      }

      render() {
        console.log('render')
        return (
          <div>
            <h1 style={{opacity:this.state.opacity}}>学不会React生命周期怎么办</h1>     --------------------①
            <button onClick={this.remove}>不活了</button>
          </div>
        )
      }
    }

    ReactDOM.render(<Life/>, document.getElementById('test'))
  </script>
1、ReactDOM.unmountComponentAtNode(document.getElementById('test'))表示卸载某一个组件。
2、componentDidMount表示组件挂在成功。
3、componentWillUnmount表示组件将要被写在之前。
4、组件中的render函数是在组件第一次渲染,以及后面的状态state中的值发生变化的时候,执行调用。
5、执行顺序是render -> componentDidMount -> componentWillUnmount
6、注意在掺入样式的时候需要使用双括号,正如①所示

出现错误:Can't perform a React state update on an unmounted component.

原因是无法在没有挂载的组件中修改state中的值。本例中是在清空之前关闭定时器。

25、声明周期

<script type="text/babel">
    class Count extends React.Component {
      // 构造函数
      constructor(props) {
        console.log('现在执行constructor中的函数')
        super(props)
      }

      state = {
        count:1
      }

      changeCount = () => {
        let {count} = this.state
        this.setState({
          count:++count
        })
      }
      // 组件挂载之前
      componentWillMount() {
        console.log('现在执行componentWillMount中的函数')
      }
      // 组件挂载完成
      componentDidMount() {
        console.log('现在执行componentDidMount中的函数')
      }

      render() {
        console.log('现在执行render中的函数')
        return (
          <div>
            <h1>当前的数字是:{this.state.count}</h1>  
            <button onClick ={this.changeCount}>点击+1</button>
          </div>
        )
      }
    }

    ReactDOM.render(<Count/>, document.getElementById('test'))
  </script>

最终的结果是:

现在执行constructor中的函数
现在执行componentWillMount中的函数
现在执行render中的函数
现在执行componentDidMount中的函数

26、countcount,以及count = count++以及count = ++ count之间的区别

1、count++和++count都具有自增1的效果。
2、count=count++没有自增的效果。
3、count=++count有自增的效果。

29、setState()执行步骤

注意:当执行到shouldComponentUpdate的时候,需要返回一个Boolen值为true才能继续。
30、forceUpdate()进行强制更新状态

使用场景:当不需要更改状态,但是想要强制更新调用render可以通过forceUpdate进行。

31、关于父子渲染中触发的生命周期函数

<script type="text/babel">
    class Father extends React.Component {
      state = {
        myCar : '保时捷'
      }

      changeCar = () => {
        this.setState({
          myCar:'奔驰C300'
        })
      }

      render() {
        return (
          <div>
            <h1>我有一辆车</h1>
            <button onClick ={this.changeCar}>我要换车</button>  
            <Son myCar = {this.state.myCar}/>
          </div>
        )
      }
    }

    class Son extends React.Component {
      render() {
        console.log('render')
        return (
          <div>
            <h4>我是子组件</h4> 
            <h4>{this.props.myCar}</h4> 
          </div>
        )
      }

      componentWillReceiveProps(props) {
        console.log("componentWillReceiveProps")
        console.log(props)
      }

      shouldComponentUpdate() {
        console.log('shouldComponentUpdate')
        return true
      }

      componentWillUpdate() {
        console.log('componentWillUpdate')
      }

      componentDidUpdate() {
        console.log("componentDidUpdate")
      }

    }

    ReactDOM.render(<Father/>, document.getElementById('test'))
  </script>
注意:componentWillReceiveProps第一次传入值的时候,不触发,第二次才进行触发
shouldComponentUpdate必须return true才能向下进行。

32、getDerivedStateFromProps

static getDerivedStateFromProps(nextProps,nextState){
    if(nextProps.value!==undefined){
        return {
            current:nextProps.value
        }
    }
    return null
}
简单来说,getDerivedStateFromProps的执行时机就是在组件初始化的时候以及组件后续更新的时候。同时getDerivedStateFromProps也可以最早的在父传子的时候获取到父组件传递给子组件的属性。由此可见,getDerivedStateFromProps很好的代替了componentWillMount以及componentWillReceiveProps。

33、getSnapshotBeforeUpdate

getSnapshotBeforeUpdate取代了componentWillUpdate
发时机为update发生的时候,在render之后、dom渲染之前返回一个值,作为componentDidUpdate的第三个参数。
简答的应用场景:
 //s比如列表更新后新的数据不断插入到数据前面,如何保证可视区依旧是之前看到的呢?(详细案例可以查看官网)
getSnapshotBeforeUpdate(){
        return this.refs.wrapper.scrollHeight
    }
    
    componentDidUpdate(prevProps,prevState,preHeight){
        this.refs.wrapper.scrollTop+=this.refs.wrapper.scrollHeight-preHeight
    }
    .....

35、diff算法

diff算法实现步骤:
1、首先获取状态更改的信息,将全部的状态数据转化成新的虚拟DOM
2、 将新的虚拟DOM和原来的虚拟DOM进行比对,根据key的值进行比对。
3、如果key相同,并且其中的内容也相同,则直接使用原来的虚拟DOM
4、如果key没有相同的,则直接将新的虚拟DOM渲染成真实DOM
5、如果key相同,并且其中也存在其他标签,也需要进行其他标签的比对,如果相同则继续使用。
6、diffing算法最低层次是标签。
7、diffing算法一般的key为id或者其他具有唯一性的值作为键。

36、React脚手架

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <!-- %PUBLIC_URL%作用就是指明图标所在文件是public文件 -->
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <!-- 进行移动端适配 -->
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <!-- 设置安卓中的搜索框中的颜色 -->
    <meta name="theme-color" content="#000000" />
    <!-- 设置搜索引擎的搜索关键字 -->
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <!-- ios手机中添加某一个特定的网页添加到手机主屏幕后的图标 -->
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <!-- 用于手机加壳 -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
 
    <title>React App</title>
  </head>
  <body>
    <!-- 当浏览器中不支持js的时候,才展示该标签 -->
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <!-- 页面渲染的跟路径 -->
    <div id="root"></div>

  </body>
</html>

37、CSS模块化

出现的原因:
当不同组件中的Css样式中存在重名的情况,当最终引入到APP.js中只会导致后面组件的样式会将前面组件的样式覆盖掉。

解决方案:

给每一个css样式文件中间添加一个modules
并且引入的时候类似于引入js

看下方的代码:

import { Component } from "react";
import HelloCss from './Hello.module.css'

export default class Hello extends Component {
  render() {
    return (
      <h1 className={HelloCss.Welcome}>hello组件</h1>
    )
  }
}

38、React中配置代理
第一种配置代理的方法:

在package.json中增添了一个属性proxy:http://localhost:5000

具体如下图所示

在package.json中追加的如下配置:
优点:配置简单,前端请求资源时可以不加任何前缀。
缺点:不能配置多个代理。

配置方法二:

在src下创建配置文件:src/setupProxy.js
编写setupProxy.js配置具体代理规则:

const proxy = require('http-proxy-middleware')

module.exports = function(app) {
  app.use(
    proxy('/api1', {  //api1是需要转发的请求(所有带有/api1前缀的请求都会转发给5000)
      target: 'http://localhost:5000', //配置转发目标地址(能返回数据的服务器地址)
      changeOrigin: true, //控制服务器接收到的请求头中host字段的值
      /*
      	changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
      	changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:3000
      	changeOrigin默认值为false,但我们一般将changeOrigin值设为true
      */
      pathRewrite: {'^/api1': ''} //去除请求前缀,保证交给后台服务器的是正常请求地址(必须配置)
    }),
    proxy('/api2', { 
      target: 'http://localhost:5001',
      changeOrigin: true,
      pathRewrite: {'^/api2': ''}
    })
  )
}
说明:
1、优点:可以配置多个代理,可以灵活的控制请求是否走代理。
2、缺点:配置繁琐,前端请求资源时必须加前缀。

相关文章