jsx语法
- 遇到{ } 就把里面的代码当js解析
- 遇到< > 就把里面的代码当html解析
声明组件
- 组件使用class声明函数组件,并且暴露出去
- 组件首字母必须大写(否则会报错)
- 声明组件使用React.Component方法
- 组件内部一定要有render(){}
- render()内部写 return ()
- 组件只能渲染一个根节点标签,就是所有的html要用一个标签包裹着
this指向问题
- react内置的方法this指向实例对象,比如state render
- 自定义的方法this为undinfied,但是写在组件内部,可以用箭头函数,this就会指向组件了,组件this是实例对象
三大对象
- state: 定义初始化数据,组件内部可以通过this.state.xx拿到
- props:可以父组件拿到传递过来数据,通过this.props.xx拿到
- ref:
组件间传值
- 父→子:
- 引入子组件并且应用上
- 把要传递的数据以标签属性的方式传递(注意jsx语法)
- 子组件中可以在this.props上拿到父组件传递过来的数据
- 子→父:
- 在父组件中声明一个方法,内写好修改数据的逻辑(回调函数形式可以接受传递过来的数据,然后做修改)
- 在标签上以标签属性的方式传递给子组件
- 子组件中用一个方法去触发props上传递过来的父组件中的方法
- 深层嵌套:
redux
react-router
- 下包 npx react-router-dom
- 引入
- 使用
- 说明
- HashRouter: 锚点链接方式 路径后面会有#
- BowserRouter:h5新特性 history.push的方式 但上线后可能会有Bug,需要后台做重定向处理
- 参数
- params: 路由传参的参数可以在props.match中去拿 具体可以打印查看
- query: props.location 中可以拿到
生命周期
- componentWillMount 组件将要更新调用 在render之前
- componentDidMoun 组件更新之后调用 在render之后
- shouldComponentUpdate 返回布尔值决定能不能让页面发生更新,如果是true就是允许,false就是不允许不做任何改变,默认是true
- componentWillUpdate 组件将要更新渲染前触发
这个生命周期可以接受两个参数() - componentDidUpdate 组件将更新渲染后触发
- componentWillReceiveProps 组件将要接受props传递的属性时触发,触发后再去触发shouldComponentUpdate 判断页面是否发生改变
- componentWillUnmount 组件卸载前执行
setState
- setState是用来改变state中状态的一个方法,可以传两个值,这个方法在可控时是异步的,不可控时是同步的。
- 对象类型 key:value 改变state中的数据
- callback 回调函数,当状态修改后触发,可以监听状态修改成功
条件渲染
- 定义数据状态
- 根据数据状态的不同来决定渲染什么代码
- 要配合jsx语法写
列表渲染
- 在jsx语法{ }中直接使用js的方法遍历生产html标签
key的作用
- key在列表渲染中很重要,在新增dom节点的时候按说是修改了state触发了render()函数重新渲染,但是打开element调试面板可以看到,只是要改变的的dom节点发生了改变,其他的没有改变,这个就是根据key这个唯一索引进行的渲染操作,只要key没有发生变化,dom就不会重新渲染,render只渲染key发生改变的那一部分。可以称为是,如果数据索引没有发生变化,只重绘发生变化的部分。这样达到节省资源节省性能消耗的目的。
表单
- 受控组件(表单双向数据绑定)
概念:通过控制组件内部的state状态进行管理 - 非受控组件
概念:通过操控dom来进行改变
请求交互
- fetch
跨域处理
- http-proxy-middleware插件 具体使用方法看文档(类似vue-cli中的proxy)
redux & react-redux
- redux:
- store: 状态仓库
用createStore方法创建,这个方法需要传入reducer作为参数 , 这个方法从redux包中取 - reducer:状态机,action中的type行为判断应该对数据做什么操作,并且返回操作结果
- actions : 行为,自定义 唯一的,调用dispatch时传入,去触发reducer状态机
- store.getState() 当数据发生变化时就会调用并返回数据的值
- store.subscribe() 监听数据变化,数据发生变化调用
- store: 状态仓库
- react-redux
需要先下载redux包,因为依赖redux,核心Provider connect 都从react-redux包中取出- Provider : 包裹标签,用法是在入口js中引入包裹住虚拟dom根标签,然后通过标签属性传值的方式把store传递到组件中去
ReactDOM.render(
,
document.getElementById('root')
);
- connect
这是一个高阶函数:就是一个函数的返回值是另一个函数- mapStateToProps:使用时创建mapStateProps方法传入参数store用来获取store中的值
- mapDispatchToProps:使用时创建mapDispatchToProps方法传入参数dispatch,在方法中调用dispatch触发reducer更新数据
- 读取数据
组建中读取数据直接通过props就可以了,因为react-redux做了包装,把数据和方法传入组件的时候包装到了props中
第三方中间件
- 第三发中间件都需要用applyMiddleware()方法包裹,这个方法从redux中取出
- redux-logger 打印redux每一步执行的行为信息
- redux-thunk
合并reducer和合并action
- 在真实项目中一定有很多action行为,也会有很多的reduce状态机去处理action,这时就需要合并统一暴露了,不然一个个引入会累死
- 合并action : bindActionCreators 这个方法从redux包中来,使用方法如下
1 // 把actions都引入到一起
import * as countActions from './store/actions'
2 // 传入actions 和disapatch 但只有当actions是方法的时候 才会成为counter的属性
const mapDispatchToProps = (dispatch) => {
return {
counter:bindActionCreators(countActions,dispatch)
}
}
3 //调用
this.props.counter.xxx()
- 合并reducer:combineReducers 这个方法从redux包中来,使用方法如下
1// 取出这个方法
import {combineReducers} from 'redux'
2// 把所有的reducer都引入到index.js中,因为要在这里生成store 通过provider传给组件
import {count,user} from './store/reducers'
3// 合并reducers创建
//合并reducer 为一个对象 然后整体暴露出去
export const reducers = combineReducers({
count,
user
})
4// 创建store
const store = createStore(reducers)
5// 读取数据
读取数据时需要需要state.xxx 因为合并的时候相当于把数据都包装到一个对象中了
const mapStateToProps = (state) => {
return {
count:state.count,
user:state.user
}
}
调试
chrome
1 安装依赖 安装插件
chrome插件 redux-devtool
依赖 redux-devtools-extension
首屏优化之组件&路由懒加载
- 直接贴链接了我就
- 1 路由懒加载的实现方案及原理 https://blog.csdn.net/weixin_34244102/article/details/94067452
- 2 使用react.lazy()方法实现路由和组件的懒加载 (适合组件式路由配置)
https://blog.csdn.net/qq_22305897/article/details/103541634 - 3 自定义方法实现路由懒加载 (适合路由集中式配置)
https://blog.csdn.net/weixin_43674509/article/details/92764687 - 4 路由集中式配置
https://blog.csdn.net/roamingcode/article/details/95235079
hook
useState: 用来创建状态和改变状态的方法
/*
count值为10
setCount是改变count的方法,不再用setState去改变状态
*/
//创建简单数据类型数据
const [count,setCount] = useState(10)
//创建复杂数据类型数据
const [obj,setObj] = useState({
name:'小米',
age:18
})
useEffect: 相当于类组件中的什么周期,
它代替了componentDidMount,componentDidUpdate,componentWillUnmount
也就是说可以在这个方法中做 发请求,监听更改数据后变化重新渲染,和解绑dom事件,清除定时器,和清除网络状态
componentDidMount: 初始化发请求
componentDidUpdate: 数据变化后重新渲染操作监听
componentWillUnmount: 解绑dom事件,清除定时器,和清除网络状态(这些操作我的另一篇文章中又提起
react中componentWillUnmount中可以做的事:https://www.jianshu.com/p/ea3cfc0a85da
useEffect 写法
//1 useEffect中要写一个回调函数
//2 可以写多个useEffect方法 每一个中做每一个生命周期中做的事以此来区分业务逻辑
useEffect(() => {
//如果直接这样写 会一直执行 页面初始化和数据更新重新渲染时都会调用这个方法
})
useEffect(() => {
//如果第二个参数传入一个数组这样写,这个方法就是componentDidMount,在页面渲染完后执行
//第二个参数是一个数组,当数组的每一项都没有发生变化,useEffect就不会重复执行,所以如果只想页面初始化调用一次的话就传一个空数组
//可以在这里面绑定一些dom事件 比如 window.addEventLister('resize',callback,boolean)
window.addEventLister('resize',callback,boolean)
//开启定时器
var time = setInterval(() => {},1000)
// 如果retrun一个函数的话 这个函数的作用就是页面卸载前触发的,相当于componentWillUnmount
// 可以做一些收尾工作,比如解绑dom事件,清除定时器
return () => {
//解绑Dom
window.removeEventLister('resize',callback,boolean)
//清除定时器
clearInterval(time)
}
},[])
// 3 副作用
useEffect(() => {
//mount后绑定的dom时间 如果该dom会被替换或者删除 绑定的事件就会失效,所以我们不能只再mount后绑定一次,要重复绑定和解绑
document.getElementById('size').addEventListener('click',Click,false)
return () => {
document.getElementById('size').removeEventListener('click',Click,false)
}
})
useMemo: 用传入的数组来判断函数是否从新执行计算
-用来性能优化,传入一个数组,数组中数据变化或为true的时候执行,在渲染过程中调用,有返回值可以参与后面逻辑渲染,有点类似vue计算属性。
import React, { useState, useMemo } from 'react'
const Counter = (props) => {
return (
//父组件传子组件 入参接受 子组件使用
{props.count}
)
}
const App = () => {
const [count, setCount] = useState(0)
// 两个参数 第一个参数是要执行的功能函数, 第二个参数[] 只传空数组就只执行一次
// useMemo 在渲染期间完成 而且有返回值 返回值可以参与渲染的,用法和useEffect一样
let double = useMemo(() => {
console.log('useMemo')
return count * 2
}, [count === 3])
return (
)
}
export default App
useCallback
- 算是useMemo简写
useMemo(() => fn)
useCallback(fn)
如果useMemo返回的是一个回到函数,使用useCallBack就可以省略掉外层包裹函数
useCallback 小例子 附说明
import React, { useCallback,useState } from 'react';
const CB = () => {
const [count,setCount] = useState(0)
const [count1,setCount1] = useState(0)
/**
* useCallback 传两个参数
* 1 回调函数
* 2 数组 数组中是另一个值 用来决定让不让第一个值的那个回调函数执行
* 3 如果 第二个参数中的值发生了变化则允许第一个参数执行,否则不允许第一个参数执行
* 4 这样可以避免一些不必要的执行 达到性能优化
*
*
* 当第一次执行useCallback中第一个参数这个回调时,不会受第二个参数影响,
* 但之后的每一次触发都先去判断第二个参数中的值有没有发生变化,如果有就让第一个参数执行,
* 如果没有就不让第一个参数执行
*/
return(
{count}
{count1}
)
}
export default CB
- useRef
- 简介:
1.用来获取dom - 用途:
- 获取输入框输入的值
- 通过输入框的值修改别的内容 (直接在获取的dom的回调函数中修改)
//如果获取的dom是个Input那么 实例.current.value就是输入框的值 const inputEl = useRef(null)
- 判断是否页面是初次加载还是重新渲染
const Ref = () => { let didMountRef = useRef(false) useEffect(() => { if(didMountRef.current){ // 页面已经加载过 现在是重绘 }else{ //页面第一次加载 didMountRef.current = true } }) }
- 简介:
- useContenx 用来父子组件传值
1 先创建实例 createContext
2 实例标签包裹子组件 并传入数据
3 在子组件中 使用useContext(实例) 传入创建的实例 就可以拿到数据 如下
import React, { useState, createContext, useContext } from 'react'
//第一步创建context实例
const MyContext = createContext()
//父组件
const Context = () => {
const count = useState(22)
return (
这里是context测试
)
}
const Child = () => {
const [state, dispatch] = useContext(MyContext)
console.log(state)
return (
{state}
)
}
useContext + useReducer 实现数据共享
- 可以传入reducer状态机和初始状态通过触发action改变数据。配合useContext可以替代redux
import React, { useState, createContext, useContext, useReducer } from 'react'
/**
* 核心思想:
* 通过 createContext创建的context对象包裹子组件,并把用useReducer创建出来的dispatch传递
* 给子组件树。在子组件中分发action触发reducer状态机函数改变数据。
*
*/
const initstate = 0
const reducer = (state, action) => {
console.log(state)
console.log(action)
switch (action.type) {
case 'add':
return state + 1
case 'reduce':
return state - 1
case 'add5':
return state + action.data
case 'reduce5':
return state - action.data
default:
return state
}
}
// 1 创建context对象
const MyContext = createContext(null)
//子组件
const Child = (props) => {
let dispatch = useContext(MyContext)
return (
{props.count}
{/* state */}
)
}
// 父组件
export default () => {
const [state, dispatch] = useReducer(reducer, initstate)
return (
hello word
{/* 父组件用context对象标签 包裹子组件树 并把dispatch传递给子组件 子组件中去分发action触发reducetion 改变数据 */}
)
}
自定义hook
1.定义一个函数,可以使用hook的提供的api,return直接返回一个可用的数据 在主组件中使用。可以把重复的逻辑提取到这个hook中。这个hook中执行逻辑返回状态。组件中直接使用就好了。比如发请求什么的。把url和data传进去。返回出请求结果。等等操作
2.名字必须是use开头
import React,{useState,useEffect} from 'react';
const useMousePosition = () => {
const [positions,setPositions] = useState({x:0,y:0})
useEffect(() => {
const updateMouse = (e:MouseEvent) => {
console.log('inner');
setPositions({x:e.clientX,y:e.clientY})
}
document.addEventListener('mousemove',updateMouse)
return () => {
document.removeEventListener('mousemove',updateMouse)
}
})
return positions
}
export default useMousePosition