前言
了解过react的同学都知道,react分类组件和函数组件,本篇作为react学习的的第一篇文章,是为了记录react中函数组件的基本知识,从项目生成开始,逐步记录react语法,组件传值,hooks函数,前后端交互,路由,状态管理等等。
因为是最基础内容,项目的结构不会很复杂。我将会在下一篇文章中记录,react对比vue的话,我们要实现一个完整的项目,react的使用和vue会有哪些区别。
项目创建
首先确保本地node环境已经配置,然后打开我们的命令行工具
全局安装creact-react-app脚手架
npm i -g create-react-app
接着我们使用creact-react-app脚手架创建项目
creact-react-app hooks-component-demo
这里的 hooks-component-demo是项目文件夹的名称,也是package.json中的项目名称。
然后我们就得到了一个最基础的react项目了
运行起来
cd hooks-component-demo
npm start
目录结构
hooks-component-demo
---node_modules
---public
--favicon.ico
--index.html // 首页的模板文件
--manifest.json // 移动端配置文件
--robots.txt
---src
--App.css
--App.js
--App.test.js
--index.js
--reportWebVitals.js
--setupTests.js
.eslintcahe
.gitignore
package.json
README.md
yarn.lock
至此我们就有了一个基本的react项目目录。由于我们主要是学习react的基本语法和声明周期这些,所以这些文件和文件中的内容暂时不展开去记录,后面抽时间了解一下每个文件的作用。
hooks函数的使用
函数式组件
要了解hooks的使用,我觉得应该先知道什么是函数式组件,以下:
1.函数式组件本质就是一个普通函数,接收一个props参数,并返回reactElement
2.函数式组件中没有this和生命周期函数,不能使用string ref
3.使用函数式组件是应该尽量减少在函数组件内部声明子函数,否则每次组件更新时,都会重新创建这个函数,导致性能比较差。
实例:src下App.js文件中
import React from 'react';
// 新建子组件
function Child(props) {
console.log('子组件接受的props', props);
return (
<div> <h2> 我是子组件->{props.name} </h2> </div>
)
}
function App() {
return (
<div>
<h1> App组件 </h1>
<Child name={'child'} />
</div>
)
}
export default App
什么是react hooks
react hooks是react16.8中新增的功能,它们使得我们无需编写类即可使用状态和其他的react功能
react hooks的优势
1.简化组件的逻辑
2.复用状态的逻辑
3.无需使用类组件编写
常用的hooks
useState
在react中,通常use开头的都是hook,所以后期我们自定义hook的时候也是遵循这套规则
useState使用
[state, setState] = useState(inittate)
--state当前对应状态,setState 修改state的方法。
useState 返回一个数组,数组第一项是初始的状态数据,数组的第二项是修改对应状态数据的方法。
import {useState,createRef} from 'react';
const inputRef = createRef()
// 新建子组件
function Child(props) {
console.log('子组件接受的props', props);
const {name,setName} = props;
return (
<div>
<h2> 我是子组件->{props.name} </h2>
<input type="text"
value={name}
ref={inputRef}
onChange={({target})=>{
setName(target.value)
}}
/>
</div>
)
}
function App() {
let [name, setName] = useState('child')
return (
<div>
<h1> App组件 </h1>
<Child name={name} setName={setName} />
</div>
)
}
export default App
多状态时,也可以传入对象,比如
const [state, setState] = useState({name: 'child',id: 1})
useEffect
useEffect相当于类组件中componentDidMount,componentDidUpdate和componentWillUnmount的一个综合体;只希望在组件挂在后执行某些事情(componentDidMount),如果我们只需要在组件挂在后执行useEffect,我们可以给一个空的数组,即:useEffect(()=>{}, [])
import {useEffect, useState} from 'react';
/**
* useEffect: 直译为副作用
* useEffect(callback, 数组) 接收两个参数
* 第一个参数为回调函数,回调函数内部可以有一个返回值,该返回值必须是一个函数,
* 且该返回值函数会在组件即将卸载的时候执行;第二个参数是一个可选数组,数组中有三个依赖,
* [依赖1,依赖2,依赖3],
**/
function Child(props){
const {name, setName, age, setAge} = props
useEffect(()=>{
console.log('组件挂载/更新/卸载了')
return ()=>{
console.log('%c 组件卸载了','color: red')
}
// 这里监听了name依赖,所以name改变,useEffect就会执行,无论age怎么改变,useEffect都不执行,
// 这样可以实现具体控制单个值,来决定是否执行useEffect的逻辑,更加细粒度的控制,提高性能
},[name]); // 如果此处依赖数组是[], 那么只会在组件挂载时执行该useEffect
return(
<div>
<p> name: {name} </p>
<input type="text" value={name} onChange={(target)=>{setName(target.value)}] />
<br/>
<p> age: {age} </p>
<input type="text" value={name} onChange={(target)=>{setName(target.value)}] />
</div>
)
}
function App(){
let [name, setName] = useState('xiaobai');
let [age, setAge] = useState(18);
let [isShow, setIsShow] = useState(true);
return (
<div>
{isShow?(<Child name={name} setName={setName} age={age} setAge={setAge} />):''}
<button onClick={()=>{setIsShow(!isShow)}} > {isShow?'隐藏':'显示'}children </button>
</div>
)
}
export default App
useRef
作用:获取真实Dom;记录组件更新之前的值。
使用
import {useState, useEffect, useRef} from 'react'
function Child(props){
const {name ,setName} = props
let [age, setAge] = useState(18)
const div = useRef(null)
const preVal = useRef({ // 记录两个参数
name, age
})
useEffect(()=>{
console.log('div current:', div.current)
console.log('preVal current:', preVal.current)
preVal.current = { // 每次组件更新后,记录新的name,age的值
name, age
}
})
return (
<div ref={div}>
<h1>child组件 </h1>
<input value={name} onChange={({target})=>{setName(target.value)}} /> <span> {name} </span> <br>
<input value={age} onChange={({target})=>{setAge(target.value)}} /> <span>{age}</span>
</div>
)
}
function App() {
let [name, setName] = useState('child')
return (
<div>
<Child name={name} setName={setName} />
</div>
)
}
export efault App
useMemo
如果我们想在组件挂载前作某些操作,可以使用useMemo
实例:
import {useMemo, useEffect, useState} from 'react'
function Child(props) {
const {name, setName} = props
const {age, setAge} = useState(18)
const val = useMemo(()=>{
console.log('组件即将挂载/即将更新')
return `姓名&{name} 年龄&{age}`
}, [name, age])
usetEffect(()=>{
console.log(组件挂载完成或更新完成)
})
console.log('组件挂载或更新)
return (
<div>
<p>{val} </p>
<input value={name} onChange={({target})=>{setName(target.value)}} /> <span> {name} </span
> <input value={age} onChange={(target)=>{setAge(target.value)}} /> <span> {age} {/span}
</div>
)
}
function App() {
let [name, setName] = useState('child')
return (
<div>
<h1> app组件</h1>
<Child name={name} setName={setName} />
</div>
)
}
Hook使用规则
只在函数中调用hook
只在最顶层使用hook,否则会报错
未完待续。。。