React函数式组件、hooks及初识路由(三)

本文介绍了React函数式组件的基础知识,包括children属性、dangerouslySetInnerHTML的使用,以及key和id的重要性和选择。接着深入探讨了React Hooks,如useState、useEffect和useRef,阐述了它们的优势和用法。文章还简要讨论了自定义Hooks的实现,并初次接触了React Router 4.0,讲解了其基本概念和主要组件,包括BrowserRouter和HashRouter的区别和使用。

一、前言

        昨天由于有一些事情耽搁,没有学习新的 react 以及发布博客. 而今天呢,这篇内容会分享类组件、函数式组件、hooks的一些方法以及初识 react 路由.接下来我们学习吧!

二、children

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

        可以自定义结构的组件的常用形式 children

当你在组件中定义了标签,你可以在父组件中使用 this.props.children 来获取标签中输入的内容

        代码案例 :

import React,{PureComponent} from 'react'

class Popwindows extends PureComponent{

  render(){
    console.log(this.props)
    let {children} = this.props
    return <div>{children}</div>
  }
}

class App extends PureComponent{

  render(){
    return (
      <div>
        <Popwindows>
          <h1>夏天快乐</h1>
          <p>夏天都快过去了</p>
        </Popwindows>
      </div>
    )
  }
}

export default App;


        浏览器效果 :
在这里插入图片描述

三、dangerouslySetInnerHTML

直接设置标签的 innerHTML

        代码案例 :

import React,{PureComponent} from 'react'

let message = `<h1>欢迎各位伙伴来到我的博客</h1>`

class App extends PureComponent{

  render(){
    return (
      <div dangerouslySetInnerHTML={{
        __html:message
      }}>
      </div>
    )
  }
}

export default App;


        浏览器效果 :
在这里插入图片描述

四、key 和 id

        key是虚拟DOM对象的标识, 在更新显示时key起着极其重要的作用。

        状态中的数据发生变化时,React 会进行新虚拟DOM 和 旧虚拟DOM 的diff比较 :

一. 旧虚拟DOM中找到了与新虚拟DOM相同的key:

(1).若虚拟DOM中内容没变, 直接使用之前的真实DOM
(2).若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM

二, 旧虚拟DOM中未找到与新虚拟DOM相同的key

根据数据创建新的真实DOM,随后渲染到到页面

        用index作为key可能会引发的问题:

一. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:

会产生没有必要的真实DOM更新,界面效果没问题, 效率低。
二. 如果结构中还包含输入类的DOM:
会产生错误DOM更新,界面有问题。
三. 果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的

        怎样选择key值:

尽量在循环中避免使用 index 下标作为 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条数据"
      },
      {
        id:5,
        content:"第6条数据"
      },
      {
        id:6,
        content:"第7条数据"
      },
    ]
  }

  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;

五、hooks

        React hooks 是React 16.8中的新增功能,无需编写类即可使用状态和其他React功能

        官方文档 : https://reactjs.org/docs/hooks-intro.html

        React Hooks 优势

简化组件逻辑
复用状态逻辑
无需使用类组件编写

        Hook 使用规则

只在最顶层使用 Hook
只在 React 函数中调用 Hook
React 函数组件中
React Hook 中 - 我自己定义 hook 时,可以调用别的hook
所有的 hook 必须 以 use

六、useState

本身是一个函数,来自react包,参数和返回值,返回一个数组
参数:作用是给创建出来的状态一个默认值
返回值:数组
元素1:当前state的值
元素2:设置新的值时,使用的一个函数

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

        代码演示 :

        app.js

import React,{useState} from 'react'
import Child from './Child'

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

function App(){
  // console.log(this);

  let [data,setName] = useState({
    name:"浩克",
    age:28
  })
  return <div>
    <Child data={data}/>
    <button onClick={()=>{
      setName({
        name:"疯狂浩克",
        age:data.age
      })
    }}>变身</button>
  </div>
}

export default App;


        创建一个Child.js组件

import React from 'react'

function Child(props){
    let {data} = props;
    return <div>
        <h1>name:{data.name}</h1>
        <h1>age:{data.age}</h1>
    </div>
}

export default Child

        我们看效果

点之前
点之后

七、useEffect

        useEffect 可以解决生命周期臃肿的问题

useEffect 你更新了信息,会触发组件信息更新
没加return就是挂载,更新. 但是会先挂载
在 return 之后,就是卸载
在最后可以绑定监听一个变量,只有这些变量变动时,useEffect 才会执行

        app.js

import React,{useState} from 'react'
import Child from './Child'

function App(){
  let [data,setName] = useState({
    name:"浩克",
    age:28
  });

  let [show,setShow] = useState(true)

  return <div>
    { show ? <Child data={data}/>:""}
    <button onClick={()=>{
      setName({
        name:"疯狂浩克",
        age:data.age
      })
    }}>变身</button>

    <button onClick={()=>{
      setShow(false)
    }}>卸载</button>
  </div>
}

export default App;


        创建一个Child.js组件

import React,{useState,useEffect} from 'react'

function Child(props){
    let {data} = props;
    let [age,setAge] = useState(8)

    // useEffect 你更新了信息,会触发组件信息更新
    // 没加return就是挂载,更新. 但是会先挂载
    // 在 return 之后,就是卸载
    // 在最后可以绑定监听一个变量,只有这些变量变动时,useEffect 才会执行
    // useEffect(()=>{
    //     console.log("组件更新了或者挂载了")
    //     return ()=>{
    //         console.log("卸载了")
    //     }
    // },[age]);

    useEffect(()=>{
        console.log("挂载了")
    },[]);

    useEffect(()=>{
        return ()=>{
            console.log("卸载了")
        }
    },[])

    useEffect(()=>{
        console.log("更新了")
    },[])


    return <div>
        <h1>name:{data.name}</h1>
        <h1>age:{age}</h1>

        <button onClick={()=>{
            setAge(++age)
        }}>点我加一岁</button>
    </div>
}

export default Child

        我们看效果
在这里插入图片描述

八、useRef

        如果父组件想要调用子组件或者子组件里面的方法和数据的话,有时候就会用到useRef

        useRef的特点 :

useRef返回一个ref对象,返回的ref对象在组件的整个生命周期保持不变

        使用 useRef 需要注意:

useRef只能在类组件中使用 class x extends React.component 或者是PureComponent,否则会报错

        案例 :

import React, {useState, useRef, createRef, useEffect } from 'react';

const Test = ()=>{
  const [ index, setIndex ] = useState(1);
  const createRefDiv = createRef();
  const useRefDiv = useRef();

  if(!createRefDiv.current){
    createRefDiv.current = index;
  }

  if(!useRefDiv.current){
    useRefDiv.current = index;
  }

  return(
    <>
      <div>createRefDiv.current: {createRefDiv.current}</div>
      <div>useRefDiv.current: {useRefDiv.current}</div>
      <div>
        <button onClick={()=>setIndex(index+1)}>改变Index</button>
      </div>
    </>
  )

}
 
export default Test;

九、useEffect与⾃定义Hooks

        代码案例 :

        app.js :

import react,{useEffect} from "react";
import {useSize,useScrollY} from "./hooks"

function App(){

  let [scrollY,setY] = useScrollY();

  useEffect(() => {
    window.onscroll = ()=>{
      setY(window.scrollY)
    }
    return () => {
      window.onscroll = null;
    }
  }, [])

  return <div>
  <ul>
    {
      [...(".".repeat(100))].map((item,index)=>{
        return <li key={index}>这是第{index}个li</li>
      })
    }
  </ul>

  <a onClick={()=>{
    setY(100)
  }}
    style={{
      position:"fixed",
      top:"50px",
      left:"200px"
    }}
  >{scrollY}</a>
</div>
    
}

export default App;

        index.js :

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(
    <App />,
  document.getElementById('root')
);


        hooks.js :

import React,{useState} from "react"

// 开头必须是 use
function useSize(){
    return {
        w: window.innerWidth,
        h: window.innerHeight
    }
}

// 获取滚动条 和 设置滚动条
function useScrollY(){
    let [scrollY,setY] = useState(window.scrollY)

    return [
        scrollY,
        (newScrollY)=>{
            window.scrollTo(0,newScrollY);
            setY(newScrollY)
        }
    ]
}

export {useScrollY};

        查看浏览器 :
在这里插入图片描述

当我们滑动鼠标滚轮时,就会自动获取到 scroll 的距离,然后点击那个数字,就会回到我们设置的 100 的那个距离

十、初识react路由

React Router4.0基本概述

React Router4.0(以下简称 RR4)遵循React的设计理念,即万物皆组件。所以 RR4 只是一堆 提供了导航功能的组件(还有若干对象和方法),具有声明式(声明式编程简单来讲就是你只需要关心做什么,而无需关心如何去做,可组合性的特点。

RR4 采用单代码仓库模型架构(monorepo),这意味者这个仓库里面有若干相互独立的包,分别是

react-router React Router 核心
react-router-dom 用于 DOM 绑定的 React Router
react-router-native 用于 React Native 的 React Router
react-router-redux React Router 和 Redux 的集成
react-router-config 静态路由配置的小助手

安装

第一步: 我们还是正常建立 react 项目

安装 React 框架 : npm i -g create-react-app
创建项目 : create-react-app 项目名称 (项目名称避免使用中文)
进入创建的项目路径 : cd 项目名字

第二步: 下载安装 react 路由

在当前项目中下载路由
npm i -S react-router-dom

BrowserRouter 和 HashRouter

        是什么?

  1. HashRouter:页面跳转原理是使用了location.hash、location.replace,并且路径中是包含/#
  2. BrowerRouter:页面跳转原理是使用了pushState、replaceState,路径不包含#直接定位到/目录下

        区别?

  1. 从页面的地址栏中可以看出HashRouter是包含#号的,而BrowerRouter是不包含#号的
  2. BrowerRouter的开启需要后端配置的,类似于Vue中的history模式。HashRouter类型于Vue中的hash模式

        怎么用?

import React from "react"
import ReactDOM from "react-dom"
// 引入 HashRouter
// import {HashRouter} from "react-router-dom";
// 引入 BrowserRouter
import {BrowserRouter} from "react-router-dom";
import './index.css';
import App from "./App"

ReactDOM.render(
  // <HashRouter>
  //   <App />
  // </HashRouter>,

  <BrowserRouter>
    <App />
  </BrowserRouter>,

  document.getElementById("root")
)

在这里插入图片描述

十一、总结

        今天学习了这么多方法,在写项目中权重挺高的,里面的注意点也希望大家能够注意.明天将会继续分享 react 的路由使用.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值