主要针对react基本语法进行学习
基本知识点
jsx是js语言的扩展,既不是字符串也不是html,但具备js的所有功能
- 实现功能
- 动态展示数据
- 调用方法
- 支持表达式
- 模板字符串拼接
- 注释
- obj对象内容输出
- 表达式(运算、三目)
- 特别属性
- JSX本身就是表达式,可以当作变量定义
- JSX 添加属性(字符串属性和动态属性)
- JSX 可以添加子元素
- JSX 只能有一个父元素
- 当我们使用但标签的时候需要进行闭合
- return 的jsx语法用()包裹起来
- 事件绑定
- 通过驼峰命名直接添加事件={事件名称}
- 事件监听传参
- 利用箭头函数内部调用事件监听的时候传递参数
- 利用bind方法返回一个新的函数在事件发生时调用,此时就可以来传递参数
- 获取事件对象
- 默认情况下不需要接收参数,且直接执行事件监听,第一个参数默认是ev
- 利用箭头函数执行事件监听的时候,通过箭头函数将ev对象传递给事件监听函数使用
- bind方法执行的时候,如果传参默认最后一个参数接受的就是ev对象
- 遍历数组
- 对数组的内容进行一系列处理后渲染到页面上
- 内联样式
- 设置的样式属性应该放在 {} 中包裹
- 内联样式默认无法支持媒体查询和伪类样式的设置
- 通过第三方库radium
- 在export到处的时候用Radium包裹可以实现伪类
- 需要在作用index.js中将App.js引入包裹Radium实现
- 外联样式
- 全局下使用的样式,通过定义在全局进行引入使用
- 组件级别的模块样式可以但设置test.module.css
- 还有可以设置组件单独一部风样式,使用styled-components
- 创建类组件
- 我们一直使用的函数组件
- 创建类组件
- 必须继承Component render
- 组件名称首字母必须是大写的,在React中区分组件和普通标记
- React中只能有一个主div标签
- 组件传值
- 在组件身上添加属性然后传递数据
- 将数据统一管理后,然后利用…操作直接传递给相应组件
- 函数组件
在函数组件通过参数props来接受,内部直接访问即可 - 类组件。
在每一个类组件中存在props属性,外部数据在这里保存,可以直接访问
- 默认值及类型校验
- 函数组件,利用.defaultProps添加默认属性
- 类组件,利用static defaultProps添加默认属性
- 组件传值如果是JSX语法格式的,需要通过props.children的方法获得
- 组件状态
- 状态就是数据,因此组件状态就是该组件自身的数据
- 数据驱动DOM: 当我们修改某一个数据的时候,DOM上的数据内容也会一起修改
- 组件状态管理:
- 在类组件当中默认就存在一个state属性,它是一个对象,可以用于保存当前组件的数据
- 之后可以通过setState方法来修改数据的值,修改后的状态会展示在DOM界面上, 在react中不能够通过this.state.name = ‘’ 来修改值
- setState是异步函数
- 可以通过async与await来解决异步问题
- 调用setState的时候可以传入回调函数,执行完才会去执行这个异步函数s
setState在使用的时候除了可以传入对象之外还可以传入一个函数
setState 在使用的时候既可以传入函数,也可以传入对象,不同点在于函数就会多次都会被执行,而对象会将后面的和前面的重叠,执行一次有效
- this指向问题
- 如果我们使用点击事件不是箭头函数,就会存在this提示undefined现象
- 我们可以通过绑定this来解决问题
onClick= {() => {this.hander()
onClick= {this.hander.bind(this)
- 单向数据流
- 单向数据流的设计原则要求我们将不同组件之间需要共享的数据定义在上层
- 自顶向下,从父组件传到子组件,通过组件传参数的方法<C1 {…this.state}>
- 子组件可以通过调用父组件传递过来的方法更改数据
- 当数据发生变化的时候,react会重新渲染组件树
如何在react中使用表单元素
受控表单
表单元素的值全部由react来进行管理,此时表单元素中的值都放在state中,所有表单元素里的值也需要从state当中获取到
与数据绑定同步
- 将state中的状态与表单的value值进行绑定 value={this.state.xxxx}
- 如何更新状态值 οnchange={方法} ev.target.value绑定
- ev.target.name===[prop]: this.setState({})
遇到细节问题
- readOnly 如果希望值是只读的,不希望被修改
- defaultValue 给默认值进行修改
class App extends Compontent {
state = {
name:'zce',
age:40
}
handler = (ev)=>{
const prop = ev.target.name
this.setState({
[prop]:ev.target.value
})
}
render(){
return(
<div>
<input name="name" value={this.state.name}
onChange={this.handler.bind(this)}>
</div>
)
}
}
非受控表单
不受react管理,表单元素的数据由DOM元素本身进行管理,表单元素的值也是存放在DOM元素里,获取的时候需要操作DOM元素
路由Hooks
react-router-dom
HashRouter:开启路由
Link: to 属性跳转到指定路由链接
Route: path component
测试代码
import {Link,Router} from 'react-router-app'
exact属性是精确只有匹配到/的时候才去显示出来
<Link to="/" exact>首页</Link>
<Link to="/home">首页</Link>
<Route path="/home" component={}>
<Route component={Notfind}>
匹配规则
- exact属性可以帮助我们精准匹配页面,不存在存在即匹配到的情况
- Switch组件包裹后可以帮助我们去除掉重复的组件内容
- 在Route规则中如果只有component属性,则是默认没有找到时展示页面
动态路由传参
匹配路由
01 路由参数占位符
02 触发操作的时候传递具体的参数
03 在具体的组件当中使用传递的参数
<Route path="/detail/:Id" component={Detail}>
查询路由参数
console打印输出发现,存在于this.props.location.search参数中,通过查询进行打印输出
路由嵌套
可以有一级二级的路由嵌套
如果想要修改路由不受影响,可以通过
$this.props.match.url代替to参数
$this.props.match.path代替path参数
路由跳转
JS原生实现
import {createHashHistory} from 'history'
<button onClick={()=>{ createHashHistory().push('/home')}}>
路由重定向
import {Redirect} from 'react-router-dom'
if(!islogin){
return <Redirect to ='/list' />
}
路由守卫
对于想要进行提前判断的路由,需要单独进行判断后再进行下一步操作
<Router path="/list" render={ props =>{
//isAuthorized是一个对象来判断并封装处理函数
if(auth.isAuthorized()){
//成立执行
}else{
//不成立执行操作
}
}}>
单独封装成一个组件来使用,使用时传入的参数与之前保持一致
export default class AuthRouteGuard extends Component
路由懒加载
import loadComponent from '@loadable/component'
const Home = loadComponent(() => import('./components/home'))
非路由组件传递路由信息
组件内的组件如何拿到路由信息
import {withRouter} from 'react-router-dom'
export default withRouter(Test)
//通过withRouter方法对外暴露
React Hooks
什么是?
01 特殊的函数
02 可以让函数式组件也具有类组件的特性
为什么?
01 数据共享
02 多个业务逻辑代码有可能会存在于同一个生命周期函数中
分别介绍
useState
可以在函数组件中保存状态的HOOK函数
参数:保存状态的初始值
返回值: 一个数组(第一个元素是当前保存的状态,第二个元素就是修改当前保存状态的方法)
const arr = useState(0)
const [state,setState] = arr
<button onClick={() => {
setState(state + 1)
}}>+1</button>
注意:
01 函数组件中可以多次使用同一个HOOK函数
02 支持简单、复杂数据类型
03 set操作也是异步的,如果同时多个对值进行操作,则会合并为一个执行
useEffect
三个生命周期(挂载、更新、卸载)的集合
参数:第一个参数函数:挂载更新完成后执行操作,return 返回函数是在卸载时执行
第二个数组参数,添加依赖,只有当数组内元素发生变化时才会被触发,数组为空情况下,则执行一次后将不再执行
useEffect(() => {
console.log('挂载更新操作完成')
return () => {
console.log('卸载时候执行')
}
},[strState])
useContext
父子组件之间的数据传递,如何给子组件添加数据以及让父组件拿到子组件中的数
const UserContext = createContext({})
const AreaContext = createContext({})
function Header () {
const userInfo = userContext(UserContext)
const AreaInfo = userContext(AreaContext)
return (
<div>
<p>{userInfo.name}</p>
<p>{userInfo.age}</p>
<p>{AreaInfo.width}</p>
</div>
)
}
useReducer
就是对不同初始值进行相同的操作方法进行封装,直接封装成reducer处理函数
const [state,dispatch] = useReducer(reducer,{num:0})
<button onClick={() => {dipatch({ type:"add" })}}> +1 </button>
useMemo
解决的问题是当父组件改变的时候,引入的子组件不再重新渲染,用memo将子组件包裹起来
const MemoHome = memo(Home)
const MemoAbout = memo(About)
function App () {
return (
<div>
<MemoHome hander={decrement} />
<MemoAbout hander={increment} />
</div>
)
}
useCallback
当子组件同样可以修改父组件里面的内容时,我们也不希望子组件被重新渲染一次,就需要用useCallback来定义我们所传递的函数
const decrement = useCallback (() => {
setAgeState(ageState - 4)
},[AgeState])
//数组中的内容是依赖,只有依赖变化的时候才会去重新渲染
不同点:
usecallback返回的就是一个函数,而usememo返回可以是多个类型,你想让他不变的内容,[]数组为空这说明数据是写死的
useRef
useRef和createRef都可以用来获取元素,但是useRef也可以来保存元素值,保存的数据只有手动修改才能发生变化
console.long(createRef.current)
console.long(useRef.current)
const obj = useRef(numState)
useImperativeHandle
相当于一个拦截器,当我们想要对内部进行操作的时候,不想给所有的权限,就可以将要进行的操作单独放在useImperativeHandle中
function Home(props,oHome) {
//获取元素
const oInput = useRef()
useImperativeHandle(oHome,()=>{
return {
setValue:()=>{
oInput.current.value="Home自己setValue"
}
}
})
return(
<div>
<h2>Home 组件</h2>
<input ref={oInput}></input>
</div>
)
}
const ForwarfHome = forwardRef(Home)
function APP() {
const oHome = useRef()
return(
<div>
<div>App组件</div>
<Home ref={oHome}></Home>
</div>
)
}
useLayoutEffect
和useEffect功能都是一样的,但是useLayoutEffect可以在元素还没有渲染的之后去执行,比如我们希望对元素样式在渲染之前进行修改就可以使用useLayoutEffect
function Home(){
const oP = useRef() //获取元素节点
useLayoutEffect(()=>{
oP.current.style.left = '0px'
oP.current.style.left = '50px'
console.log('挂载|更新', useLayoutEffect) return() => {console.log('卸载')}
})
return(
<div>
<p ref={oP}>Home组件中的P元素</p>
</div>
)
}
自定义Hooks实现
可以在我们自定义函数中直接调用Hooks的函数,但前提是函数前缀必须加上use,这样才能被作为钩子去使用