react创建项目&&常见的三大Hook

react创建项目&&常见的三大Hook

创建react脚手架项目

全局安装 create-react-app 工具:

npm i -g create-react-app

查看安装工具的版本号,注意V大写

create-react-app -V

进入要创建的文件目录创建react项目,名为:react_project

create-react-app react_project

启动项目会默认3000端口号打开浏览器

npm start

目录结构

node_modules/: 存放项目依赖包的目录。该目录会在运行 npm install 后生成

public/: 存放公共静态资源文件的目录
    favicon.ico: 浏览器标签上的图标。
    index.html: 主页面。
    logo192.png
    log512.png:logo图
    manifest.json: 应用加壳的配置文件,定义了应用的图标、启动配置、显示模式等。
    robots.txt:爬虫协议文件,控制哪些内容可以被抓取和索引,优化搜索引擎的表现,减少服务器负担,并保护网站的敏感数据。
    
src/:源码文件夹
    App.css: App 组件的样式文件。
    App.js: 主组件文件,包含应用的主要内容。
    App.test.js: 对 App 组件的测试文件。
    index.css: 全局样式文件。
    index.js: 应用的入口文件,将 App 组件渲染到 HTML 文件中。
    logo.svg: 默认的 React Logo 图像文件。
    reportWebVitals.js: 用于记录和报告 Web Vitals 性能指标的文件。

.gitignore: Git 忽略文件列表,指定哪些文件和目录不应该被版本控制系统跟踪。

package.json: 项目配置文件,包含项目的依赖、脚本和其他元数据。

README.md: 项目的说明文件,通常包含项目的介绍、安装和使用说明。

package-lock.json: 自动生成的文件,锁定依赖的版本,以确保项目在不同的环境中安装一致的版本。

React Hooks

hooks是什么?

是react 16.8 引入的功能,允许在函数组件中使用state状态和其他react特性,而无需编写类组件

三个常用的Hook

  • React.useState()
  • React.useEffect()
  • React.useRef()

useState Hook

用于在函数组件中添加状态,返回一个状态变量和一个函数,用于更新这个状态变量

eg(Components/index.jsx):

类式组件写法:

import React from 'react'

class Demo extends React.Component {
  state = {count: 0}
  
  add = ()=>{
    this.setState(state => ({count:state.count+1}))
  }
  render () {
    return (
      <div>
        <h1>和为{this.state.count}</h1>
        <button onClick={this.add}>点我加1</button>
      </div>
    )
  }
}

函数式组件写法:

import React,{useState} from 'react'

function Demo(){
  const [count,setCount] = useState(0)
  const [sex,setSex] = useState('女')
  const [name,setName] = useState('小白')
  
  function add(){
    // console.log('点击');
    // setCount(count+1) //第一种写法
    setCount(count => count+1) //第二种
  }
  function changeSex(){
    setSex(sex => (sex === '男'? '女': '男'))
  }
  function changeName(){
    setName(name => name="小黑")
  }
    return (
      <div>
        <h1>和为:{count}</h1>
        <h2>我是:{name}</h2>
        <h2>性别:{sex}</h2>
        <button onClick={add}>点我加1</button>
        <button onClick={changeName}>点我改姓名</button>
        <button onClick={changeSex}>点我改性别</button>
      </div>
    )
}

export default Demo

上述代码中useState(initialState):

  • useState是一个函数,他接受一个初始状态initialState作为参数
  • 返回一个数组,数组第一个元素是当前的状态值,第二个元素是一个函数,用于更新状态

setXXX()两种写法:

  • setXXX(newValue):参数为非函数值,直接指定新的状态值,内部用其覆盖原来的状态值
  • setXXX(value => newValue):参数为函数,接收原来的状态值,返回新的状态值,内部用其覆盖原来的状态值

useEffect Hook

用于处理副作用操作(数据获取、订阅、手动操作DOM等)。允许在函数组件中执行这些副作用操作,而不需要使用类组件的生命周期。

  • 类式组件写法:
import React from 'react'
import ReactDOM from 'react-dom'
import root from '../../index'

// 类式组件
class Demo extends React.Component {
  state = {count: 0}  
  add = ()=>{
    this.setState(state => ({count:state.count+1}))
  }
  unmount = ()=>{
    if(root){
      root.unmount()
    }
  }
  componentDidMount(){
    // console.log('组件挂载完成')
    this.timer = setInterval(()=>{
      this.setState(state => ({count:state.count+1}))
    },1000)
  }
  componentWillUnmount(){
    // console.log('组件将要卸载')
    clearInterval(this.timer)
  }
  render () {
    return (
      <div>
        <h1>和为{this.state.count}</h1>
        <button onClick={this.add}>点我加1</button>
        <button onClick={this.unmount}>卸载</button>
      </div>
    )
  }
}
export default Demo
  • 函数式组件写法:
import React,{useEffect,useState} from 'react'
import ReactDOM from 'react-dom'
import root from '../../index'


function Demo(){
  const [count,setCount] = useState(0)
  
  // useEffect(()=>{
  //   console.log('-----');    
  // },[count])
/*   
  注意:上面的空数组,表示谁也不监测。
  不写的话就是全都监测(组件挂载和更新都会监测到)
  具体监测到什么就写什么,比如[count] 就只监测count
   */
  useEffect(()=>{
    let timer = setInterval(()=>{
      setCount(count => count+1)
    },3000)
    return ()=>{
      clearInterval(timer)
    }
  },[])
  function add(){
    setCount(count => count+1)
  }
  function onmount(){
    if(root){
      root.unmount();
    }
  }
  return (
    <div>
      <h1>和为:{count}</h1>
      <button onClick={add}>点我加1</button>
      <button onClick={onmount}>卸载</button>
    </div>
  )
}
export default Demo

useRef Hook

类式组件写法:

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

// 类式组件
class Demo extends React.Component {
  state = {count: 0}  
  myRef = React.createRef()
  add = ()=>{
    this.setState(state => ({count:state.count+1}))
  }
  show = ()=>{
    alert(this.myRef.current.value)
  }
  unmount = ()=>{
    if(root){
      root.unmount()
    }
  }
  componentDidMount(){
    // console.log('组件挂载完成')
    this.timer = setInterval(()=>{
      this.setState(state => ({count:state.count+1}))
    },1000)
  }
  componentWillUnmount(){
    // console.log('组件将要卸载')
    clearInterval(this.timer)
  }
  render () {
    return (
      <div>
        <h1>和为{this.state.count}</h1>
        <input type="text" ref= {this.myRef} />
        <button onClick={this.add}>点我加1</button>
        <button onClick={this.unmount}>卸载</button>
        <button onClick={this.show}>弹窗显示数据</button>
      </div>
    )
  }
}

函数式组件写法:

import React,{useState,useEffect,useRef} from 'react'
import root from '../../index'

function Demo(){
  const [count,setCount] = useState(0)
  const myRef = useRef()

  useEffect(()=>{
    let timer = setInterval(()=>{
      setCount(count => count+1)
    },3000)
    return ()=>{
      clearInterval(timer)
    }
  },[])
  function add(){
    setCount(count => count+1)
  }
  function onmount(){
    if(root){
      root.unmount();
    }
  }
  function show (){
    alert(myRef.current.value)
  }
  return (
    <div>
      <h1>和为:{count}</h1>
      <input type="text" ref = {myRef} />
      <button onClick={add}>点我加1</button>
      <button onClick={onmount}>卸载</button>
      <button onClick={show}>点我显示输入框信息弹窗</button>
    </div>
  )
}

export default Demo

遇到的问题:

问题1:useEffect生命周期函数为什么会被进行两次调用?

问题分析:

这部分代码,我看到控制台--------打印了两次,其原因是react的严格模式会在开发环境下对某些生命周期函数(包括useEffect)进行两次调用,这是为了验证副作用的影响,生产模式不会发生这种情况

解决方法:

在indedx.js入口文件中,删除或者注释掉React.StrictMode即可

问题2:react组件卸载报错问题,如下:
报错显示及分析:
  • unmountComponentAtNode is deprecated and will be removed in the next major release. 报错提示是因为unmountComponentAtNode已经被弃用
  • You are calling ReactDOM.unmountComponentAtNode() on a container that was previously passed to ReactDOMClient.createRoot(). This is not supported. Did you mean to call root.unmount()?尝试用旧的卸载方法 ReactDOM.unmountComponentAtNode() 去卸载一个之前使用新的 ReactDOM.createRoot() 方法创建的 React 根节点。这两者是不兼容的。
  • unmountComponentAtNode(): The node you're attempting to unmount was rendered by React and is not a top-level container. Instead, have the parent component update its state and rerender in order to remove this component.你试图卸载的节点不是一个顶层容器节点。换句话说,你可能在试图卸载由 React 管理的子组件,而不是根节点。
解决方法:

通过将root导出并在其他地方导入来管理卸载组件,这是因为直接管理root对象是因为它提供了对react根结点更好的控制,尤其是在react18及以上版本时。他确保能正确地卸载和管理组件,而不会引发错误或与旧版本产生冲突

操作步骤:
  • 在入口文件index.js导出root:
export default root;
  • 在要卸载的组件文件中导入root:
import root from '../../index' //根据自己路径调整

  function onmount(){
    if(root){
      root.unmount();
    }
  }

<button onClick={onmount}>卸载</button>
posted @ 2024-09-01 22:45  淡然置之  阅读(46)  评论(0编辑  收藏  举报