React 属性, 函数式组件以及Hook

Posted ZZZ --- jh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React 属性, 函数式组件以及Hook相关的知识,希望对你有一定的参考价值。


五个属性: PureComponent、ref、children、dangerouslySetInnerhtml、key

React的五个属性

PureComponent

个人理解是PureComponent 是类组件的情况下,它是用来继承的

pureComponent 提供了一个具有浅比较,的shouldComponrentUpdate方法其他和component完全一致

是react中创建组件的一种方式,可以减少不必要的更新,易于实施,进而提升性能,每次更新会自动帮你对更新前后的props和state进行一个简单对比, 来决定是否进行更新.只要把继承类从 Component 换成 PureComponent 即可,可以减少不必要的 render 操作的次数,从而提高性能,而且可以少写 shouldComponentUpdate 函数,节省了点代码。

import React, {PureComponent, Component} from 'react';

class App extends PureComponent {

  state = {
    name:'张三',
    list:["张三01","张三02","张三03"]
  }

  render(){
    let {name, list} = this.state;
    return (
      <div>
        <h1>{name}</h1>
        <ul>
          {
            list.map((item,index)=>{
              return <li key={index}>{item}</li>
            })
          }
        </ul>

        <button onClick={()=>{
          this.setState({name:'yyqx'})
        }}>升级</button>

        <button onClick={()=>{
          list.push('新人');
          this.setState({list:[...list]})
        }}>扩大</button>

      </div>
    )
  }
}

export default App;

以上这个案例当继承PureComponent时,list:[...list]必须写成这样扩大的这个按钮才会新增数据的; 当继承Component时, list:[...list]也可以写成list

ref

  • 注意: 再组件挂载完成之后及更新之后使用

  • 旧版 ref —> 字符串类型绑定

    先安装npm i better-scroll

    再引入 import BScroll from "better-scroll";

    import React, {PureComponent, Component} from 'react';
    import BScroll from "better-scroll";
    // new BScroll()
    
    let list = [...('.'.repeat(100))];
    // console.log(list);
    
    class App extends PureComponent {
      // 组件挂载完成之后
      componentDidMount(){
        // 通过this.refs绑定ref的名字来获取dom节点
        // console.log(this.refs.box);
        new BScroll(this.refs.box);
      }
    
      render(){
        return (
          <div style={{
            height:'300px',
            border:'1px solid red',
            overflow:'hidden'
          }} 
          ref='box'
          >
            <ul style={
              {margin:0,padding:0,listStyle:'none'}
            }>
              {
                list.map((item,index)=>{
                  return <li key={index}>这是第{index}个li</li>
                })
              }
            </ul>
          </div>
        )
      }
    }
    export default App;
    

    这个案例中滚动效果是可以实现的,但是控制台会给一个提示Warning: A string ref, "box", has been found within a strict mode tree. String refs are a source of potential bugs and should be avoided. We recommend using useRef() or createRef() instead. Learn more about using refs safely here (字符串ref, “box”,在严格模式树中被发现。字符串引用是潜在错误的来源,应该避免); 可以把index.js中的<React.StrictMode></React.StrictMode>这个标签删除掉就不会警告了; 此时就要用到下面的这个方法了.

  • 新版 ref —> createRef()

    通过在class中使用createRef()方法创建一些变量,可以将这些变量绑定到标签的ref中,那么该变量的current则指向绑定的标签dom

    import React, {PureComponent, Component, createRef} from 'react';
    import BScroll from "better-scroll";
    
    // new BScroll()
    
    let list = [...('.'.repeat(100))];
    // console.log(list);
    
    class App extends PureComponent {
      box = createRef();
    
      componentDidMount(){
        // console.log(this);
        // console.log(this.box.current);
        new BScroll(this.box.current)
      }
    
      render(){
    
        return (
          <div style={{
            height:'300px',
            border:'1px solid red',
            overflow:'hidden'
          }} 
          ref = {this.box}
          >
            <ul style={
              {margin:0,padding:0,listStyle:'none'}
            }>
              {
                list.map((item,index)=>{
                  return <li key={index}>这是第{index}个li</li>
                })
              }
            </ul>
          </div>
        )
      }
    }
    
    export default App;
    

children

  • 组件标签对之间的内容会被当做一个特殊的属性props.children传入组件内容

    import React, {PureComponent} from 'react';
    
    class Child extends PureComponent{
      render(){
        console.log(this);
        let {children} = this.props;
        return <div>{children}</div>
      }
    }
    
    class App extends PureComponent {
      render(){
        return (
          <div>
            <Child >
              {/* <h1>今天的天气很不错</h1>
              <p>明天的天气也还行</p> */}
              {
                ['哈哈','拉拉']
              }
            </Child>
          </div>
        )
      }
    }
    
    export default App;
    
  • 可以自定义结构的组件的常用形式

    • children
    • 传递函数
    • 传递子组件
    import React, {PureComponent} from 'react';
    
    class Popwindow extends PureComponent{
      state = {
        close:false
      }
    
      render(){
        // console.log(this);
        let {close} = this.state;
        let {children} = this.props;
        return (
          <div style={{
            border:'3px solid #ccc',
            display: close ? "none" : 'block'
          }}>
            {children}
    
            <button onClick={()=>{
              this.setState({
                close:true
              })
            }}>关闭</button>
    
          </div>
        )
      }
    }
    
    class App extends PureComponent {
      state = {
        show:false,
        man:false
      }
    
      render(){
        let {show, man} = this.state;
        return (
          <div>
            {show?(<Popwindow >
              <h1>yyqx</h1>
              <p>qzh</p>
            </Popwindow>):''}
    
            {man?(<Popwindow >
              <h1>qxx</h1>
              <p>byg</p>
            </Popwindow>):''}
    
            <button onClick={()=>{
              this.setState({show:true})
            }}>显示弹框1</button>
    
            <button onClick={()=>{
              this.setState({man:true})
            }}>显示弹框2</button>
            
          </div>
        )
      }
    }
    
    export default App;
    

dangerouslySetInnerHTML

  • 直接设置标签的innerHTML

  • 要接收的插值只能是一个对象

  • 有个固定的属性: __html

  • 可以用来接收数据,但是接收的只能是后端的数据,后端服务器发送过来的数据是校检过的,是安全的;不要接收前端自己写的数据

  • import React, {PureComponent} from 'react';
    
    let message = `<h1>yyqx</h1>
                  <p>qzh</p>`
    
    class App extends PureComponent {
      render(){
        return (
          <div dangerouslySetInnerHTML={{
            __html:message
          }}>
            
          </div>
        )
      }
    }
    
    export default App;
    

key的问题

  • 在react,组件每次更新时,会生成一个虚拟DOM, 和原油的虚拟DOM进行对比; 如果在批量生成一组元素,那么react就会根据key值去做对比

  • 一个列表中的每一项key是惟一的, 如果列表中发生顺序等操作变化,key一定要用数据的id

  • import React, {PureComponent} from 'react';
    
    class App extends PureComponent {
      state = {
        data:[
          {
            id:0,
            content:'第1条数据'
          },
          {
            id:1,
            content:'第2条数据'
          },
          {
            id:2,
            content:'第3条数据'
          },
          {
            id:3,
            content:'第4条数据'
          },
          {
            id:4,
            content:'第5条数据'
          }
        ]
      }
    
      render(){
        let {data} = this.state;
        return (
          <div >
            {
              data.map((item,index)=>{
                return <p key={item.id}>
                  {item.content}
    
                  <a onClick={()=>{
                    data = data.filter(itemData=>itemData!==item)
                    this.setState({
                      data:[...data]
                    })
                  }}>删除</a>
                  
                </p>
              })
            }
          </div>
        )
      }
    }
    
    export default App;
    

函数式组件

16.7版本之后新增的

函数式组件中, 没有state和生命周期; 所以又称为无状态组件; 在早期16.7(react)版本中,被当前纯渲染组件来用

函数名就是组件名;

组件的第0个参数是 props - 接收父级传过来的信息

没有this; 没有state和生命周期;

必须要有return, return里面定义的是该组件渲染的内容

在16.7之前函数组件一直当做渲染组件来使用

<!-- app.js -->
import React from 'react';

function Child(props){
  return <h1>{props.info} </h1>
}

function App(){
  // console.log(this); // undefined
  // return <div>哈哈哈</div>
  return <Child info='呵呵' /> 
}

export default App;


React hooks

react hooks 是react16.8中的新增功能. 无需编写class类的情况下使用state状态和其他react功能.

英文文档参考: https://reactjs.org/docs/hooks-intro.html

中文文档参考: https://reactjs.bootcss.com/docs/hooks-intro.html

什么是Hook

Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。Hook 不能在 class 组件中使用 —— 这使得你不使用 class 也能使用 React.

React Hooks的优势

  • 简化组件逻辑
  • 复用状态逻辑
  • 无需使用类组件编写
  • 完全可选的
  • 100%向后兼容. 不包含任何破坏性改动
  • 现在可用

常用Hook

  • useState – 让函数式组件拥有状态

    let [状态的值,修改状态的方法] = useState(状态的初始值);

    let [state, setState] = useState(initialState);

    useState 唯一的采纳数就是初始state.

    <!-- app.js -->
    import React, {useState} from 'react';
    import Child from './Child'
      // let [状态的值,修改状态的方法] = useState(状态的初始值);
    function App(){
      let [data,setData] = useState({
        name:"yyqx",
        age:20
      });
    
      return <div>
        <Child data={data} />
        <button onClick={()=>{
          setData({
            name:'Jackson',
            age:data.age
          });
        }}>
          变身
        </button>
      </div>
    }
    export default App;
    
    <!-- Child.js -->
    import React from 'react';
    
    function Child(props){
      console.log(props);
      let {data} = props;
      return <div>
        <h1>name:{data.name} </h1>
        <h1>age:{data.age} </h1>
      </div>
    }
    export default Child;
    
  • useEffect – 副作用,取代生命周期

    相当于类组件中的 componentDidMount(挂载完成);   componentDidUpdate(数据更新完成);  componentWillUnmount(即将卸载) 这三个的集合体.

    可以在组件中多次使用useEffect;

    useEffect 做了什么? 通过使用这个 Hook,可以告诉 React 组件需要在渲染后执行某些操作。React 会保存你传递的函数并且在执行 DOM 更新之后调用它。

    为什么在组件内部调用 useEffectuseEffect 放在组件内部让我们可以在 effect 中直接访问 count state 变量(或其他 props)。不需要特殊的 API 来读取它 —— 它已经保存在函数作用域中。Hook 使用了 javascript 的闭包机制,而不用在 JavaScript 已经提供了解决方案的情况下,还引入特定的 React API.

    useEffect 会在每次渲染后都执行吗? 是的,默认情况下,它在第一次渲染之后每次更新之后都会执行。React 保证了每次运行 effect 的同时,DOM 都已经更新完毕。

    <!-- Child.js -->
    import React,{ useState, useEffect } from 'react';
    
    function Child(props){
      let {data} = props;
      let [age,setAge] = useState(8);
    
      // 第二个参数数组中放的是监测的内容
      useEffect(()=>{
         console.log('挂载了');
      },[])
        
      // 卸载的时候记得卸载return里面
      useEffect(()=>{
        return ()=>{
          console.log('卸载了');
        }
      },[])
    
      useEffect(()=>{
        console.log('更新了');
      },[age])
    
      return <div>
        <h1>name:{data.name} </h1>
        <h1>age:{age} </h1>
    
        <button onClick={()=>{
          setAge(++age)
        }}>涨一岁</button>
    
      </div>
    }
    export default Child;
    
    <!-- app.js -->
    import React, {useState} from 'react';
    import Child from './Child'
    
    function App(){
      let [data,setData] = useState({
        name:"yyqx",
        age:20
      });
      let [show,setShow] = useState(true);
    
      return <div>
        {show ? <Child data={data} /> : ""}
    
        <button onClick={()=>{
          setData({
            name:'Jackson',
            age:data.age
          });
        }}>
          变身
        </button>
    
        <button onClick={()=>{
          setShow(<

    以上是关于React 属性, 函数式组件以及Hook的主要内容,如果未能解决你的问题,请参考以下文章

    React 属性, 函数式组件以及Hook

    react讲解(函数式组件,react hook)

    react讲解(函数式组件,react hook)

    react讲解(函数式组件,react hook)

    react讲解(函数式组件,react hook)

    React的hook之useState简单实现