这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战vue
本文做为本人学习总结之用,同时分享给你们,适合入门的react小白
由于我的技术有限,若是有发现错误或存在疑问之处,欢迎指出或指点!不胜感谢!react
动做的对象git
包含两个属性github
编码:ajax
//该模块是用于定义action对象中type类型的常量值,目的只有一个:便于管理的同时防止单词写错
import {ADD_PERSON} from '../constant'
//专门为组件生成action对象
export const addPerson = data => ({type:ADD_PERSON,data})
复制代码
const initState = xx
export default function xxxReducer(preState =initState, action) {
const {type ,data} = action
switch (type) {
case JIA:
return preState+1
default :
return preState
}
}
复制代码
//引入createStore,专门用于建立redux中最为核心的store对象
import {createStore} from 'redux'
//引入为Count组件服务的reducer
import countReducer from './count_reducer'
//暴露store
export default createStore(countReducer)
复制代码
此对象的功能?npm
getState()
: 获得state
dispatch(action)
: 分发action
, 触发reducer
调用, 产生新的state
subscribe(listener)
: 注册监听, 当产生了新的state
时, 自动调用componentDidMount(){
//检测redux中状态的变化,只要变化,就调用render
store.subscribe(()=>{
this.setState({})
})
}
store.dispatch(createIncrementAction(value*1))
store.getState()
复制代码
做用:建立包含指定reducer的store对象redux
store.getState()
store.dispatch({type:'INCREMENT', number})
store.subscribe(render)
做用:应用上基于redux的中间件(插件库)api
做用:合并多个reducer函数数组
1. redux默认是不能进行异步处理的,缓存
2. 某些时候应用中须要在redux 中执行异步任务(ajax, 定时器)
必须下载插件:
npm install --save redux-thunk
在store.js文件中引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'
UI组件
容器组件
import {Provider} from 'react-redux'
<Provider store={store}>
<App/>
</Provider>
复制代码
//引入Count的UI组件
import CountUI from '../../components/Count'
//引入action
import {
createIncrementAction,
} from '../../redux/count_action'
//引入connect用于链接UI组件与redux
import {connect} from 'react-redux'
/* 1.mapStateToProps函数返回的是一个对象; 2.返回的对象中的key就做为传递给UI组件props的key,value就做为传递给UI组件props的value 3.mapStateToProps用于传递状态 */
function mapStateToProps(state){
return {count:state}
}
/* 1.mapDispatchToProps函数返回的是一个对象; 2.返回的对象中的key就做为传递给UI组件props的key,value就做为传递给UI组件props的value 3.mapDispatchToProps用于传递操做状态的方法 */
function mapDispatchToProps(dispatch){
return {
jia:number => dispatch(createIncrementAction(number))
}
}
//使用connect()()建立并暴露一个Count的容器组件
export default connect(mapStateToProps,mapDispatchToProps)(CountUI)
//简写
export default connect(
state => ({count:state}),
{jia:createIncrementAction}
)(Count)
复制代码
setState(stateChange, [callback])
------对象式的setState
1.stateChange为状态改变对象(该对象能够体现出状态的更改)
2.callback是可选的回调函数, 它在状态更新完毕、界面也更新后(render调用后)才被调用
复制代码
setState(updater, [callback])
------函数式的setState
1.updater为返回stateChange对象的函数。
2.updater能够接收到state和props。
3.callback是可选的回调函数, 它在状态更新、界面也更新后(render调用后)才被调用。
复制代码
总结:
//对象式的setState
//1.获取原来的count值
const {count} = this.state
//2.更新状态
this.setState({count:count+1},()=>{
console.log(this.state.count);
})
//console.log('12行的输出',this.state.count); //0
//函数式的setState
this.setState( (state,props) => ({count:state.count+1}),() =>{
console.log(state.count)
})
复制代码
//1.经过React的lazy函数配合import()函数动态加载路由组件 ===> 路由组件代码会被分开打包
const Login = lazy(()=>import('@/pages/Login'))
//2.经过<Suspense>指定在加载获得路由打包文件前显示一个自定义loading界面
fallback包裹一个通常组件也能够
<Suspense fallback={<h1>loading.....</h1>}>
<Switch> <Route path="/xxx" component={Xxxx}/> <Redirect to="/login"/> </Switch>
</Suspense>
复制代码
React Hook/Hooks是什么?
三个经常使用的Hook
State Hook: React.useState()
Effect Hook: React.useEffect()
Ref Hook: React.useRef()
State Hook
setXxx()2种写法:
Effect Hook
useEffect(() => {
// 在此能够执行任何带反作用操做
return () => { // 在组件卸载前执行
// 在此作一些收尾工做, 好比清除定时器/取消订阅等
}
}, [stateValue]) // 若是指定的是[], 回调函数只会在第一次render()后执行
复制代码
能够把 useEffect Hook 看作以下三个函数的组合
componentDidMount()
componentDidUpdate()
componentWillUnmount()
Ref Hook
function Demo(){
const [count,setCount] = React.useState(0)
const myRef = React.useRef()
React.useEffect(()=>{
let timer = setInterval(()=>{
setCount(count => count+1 )
},1000)
return ()=>{
clearInterval(timer)
}
},[])
//加的回调
function add(){
//setCount(count+1) //第一种写法
setCount(count => count+1 )
}
//提示输入的回调
function show(){
alert(myRef.current.value)
}
//卸载组件的回调
function unmount(){
ReactDOM.unmountComponentAtNode(document.getElementById('root'))
}
return (
<div> <input type="text" ref={myRef}/> <h2>当前求和为:{count}</h2> <button onClick={add}>点我+1</button> <button onClick={unmount}>卸载组件</button> <button onClick={show}>点我提示数据</button> </div>
)
}
复制代码
做用:能够不用必须有一个真实的DOM根标签了
<Fragment key={1}> //能参与遍历
<input type="text"/>
<input type="text"/>
</Fragment>
或者
<>
<input type="text"/>
<input type="text"/>
</>
复制代码
一种组件间通讯方式, 经常使用于【祖组件】与【后代组件】间通讯
const XxxContext = React.createContext()
<xxxContext.Provider value={数据}>子组件</xxxContext.Provider>
后代组件读取数据:
//第一种方式:仅适用于类组件
static contextType = xxxContext // 声明接收context
this.context // 读取context中的value数据
//第二种方式: 函数组件与类组件均可以
<xxxContext.Consumer>
{
value => ( // value就是context中的value数据
要显示的内容
)
}
</xxxContext.Consumer>
复制代码
注意:在应用开发中通常不用context, 通常都它的封装react插件
//建立Context对象
const MyContext = React.createContext()
const {Provider,Consumer} = MyContext
export default class A extends Component {
state = {username:'tom',age:18}
render() {
const {username,age} = this.state
return (
<div className="parent"> <h3>我是A组件</h3> <h4>个人用户名是:{username}</h4> <Provider value={{username,age}}> <B/> </Provider> </div>
)
}
}
class B extends Component {
render() {
return (
<div className="child"> <h3>我是B组件</h3> <C/> </div>
)
}
}
/* class C extends Component { //声明接收context static contextType = MyContext render() { const {username,age} = this.context return ( <div className="grand"> <h3>我是C组件</h3> <h4>我从A组件接收到的用户名:{username},年龄是{age}</h4> </div> ) } } */
function C(){
return (
<div className="grand"> <h3>我是C组件</h3> <h4>我从A组件接收到的用户名: <Consumer> {value => `${value.username},年龄是${value.age}`} </Consumer> </h4> </div>
)
}
复制代码
项目的2个问题
只要执行setState(),即便不改变状态数据, 组件也会从新render()
只当前组件从新render(), 就会自动从新render子组件 ==> 效率低
效率高的作法:
只有当组件的state或props数据发生改变时才从新render()
缘由:
Component中的shouldComponentUpdate()老是返回true
解决:
办法1:
重写shouldComponentUpdate()方法
比较新旧state或props数据, 若是有变化才返回true, 若是没有返回false
复制代码
办法2:
使用PureComponent
PureComponent重写了shouldComponentUpdate(), 只有state或props数据有变化才返回true
注意:
只是进行state和props数据的浅比较, 若是只是数据对象内部数据变了, 返回false
不要直接修改state数据, 而是要产生新数据
复制代码
项目中通常使用PureComponent来优
import React, { PureComponent } from 'react'
export default class Parent extends PureComponent {
state = {carName:"奔驰c36",stus:['小张','小李','小王']}
addStu = ()=>{
const {stus} = this.state
this.setState({stus:['小刘',...stus]})
}
changeCar = ()=>{
this.setState({carName:'迈巴赫'})
}
/* shouldComponentUpdate(nextProps,nextState){ // console.log(this.props,this.state); //目前的props和state // console.log(nextProps,nextState); //接下要变化的目标props,目标state return !this.state.carName === nextState.carName } */
render() {
console.log('Parent---render');
const {carName} = this.state
return (
<div className="parent"> <h3>我是Parent组件</h3> {this.state.stus} <span>个人车名字是:{carName}</span><br/> <button onClick={this.changeCar}>点我换车</button> <button onClick={this.addStu}>添加一个小刘</button> <Child carName="奥拓"/> </div>
)
}
}
class Child extends PureComponent {
/* shouldComponentUpdate(nextProps,nextState){ console.log(this.props,this.state); //目前的props和state console.log(nextProps,nextState); //接下要变化的目标props,目标state return !this.props.carName === nextProps.carName } */
render() {
console.log('Child---render');
return (
<div className="child"> <h3>我是Child组件</h3> <span>我接到的车是:{this.props.carName}</span> </div>
)
}
}
复制代码
\
如何向组件内部动态传入带内容的结构(标签)?
Vue中:
使用slot技术, 也就是经过组件标签体传入结构 <AA><BB/></AA>
React中:
- 使用children props: 经过组件标签体传入结构
- 使用render props: 经过组件标签属性传入结构, 通常用render函数属性
复制代码
children props
<A>
<B>xxxx</B>
</A>
{this.props.children}
复制代码
问题: 若是B组件须要A组件内的数据, ==> 作不到
render props
<A render={(data) => <C data={data}></C>}></A>
A组件: {this.props.render(内部state数据)}
C组件: 读取A组件传入的数据显示 {this.props.data}
理解:
错误边界:用来捕获后代组件错误,渲染出备用页面
特色:
只能捕获后代组件生命周期产生的错误,不能捕获本身组件产生的错误和其余组件在合成事件、定时器中产生的错误
使用方式:
getDerivedStateFromError配合componentDidCatch
// 生命周期函数,一旦后台组件报错,就会触发
//当Parent的子组件出现报错时候,会触发getDerivedStateFromError调用,并携带错误信息
static getDerivedStateFromError(error){
console.log('@@@',error);
return {hasError:error}
}
componentDidCatch(){
console.log('此处统计错误,反馈给服务器,用于通知编码人员进行bug的解决');
}
复制代码