react(含hooks)同步获取state值
环境
"dependencies": {
"babel-plugin-transform-decorators-legacy": "^1.3.5",
"customize-cra": "^1.0.0",
"rc-form": "^2.4.11",
"react": "^17.0.1",
"react-app-rewired": "^2.1.8",
"react-dom": "^17.0.1",
"react-router-dom": "^5.2.0",
"react-scripts": "^4.0.1",
"redux": "^4.0.5"
},
代码示例
hooks
import {useState} from "react";
export default function Pre04SetStateSync() {
const [counter, setCounter] = useState(0)
const add = () => {
setCounter(counter + 1)
console.log({counter})
}
return <>
<h3>同步SetState</h3>
<p>请观察控制台</p>
<button onClick={add}>counter: {counter}</button>
</>
}
class
export default class Pre04SetStateSync extends React.Component{
state = {
counter:0
}
add = () => {
this.setState({counter:this.state.counter + 1})
console.log('~~this.state.counter',this.state.counter)
}
render() {
return <>
<h3>同步SetState</h3>
<p>请观察控制台</p>
<button onClick={this.add}>counter: {this.state.counter}</button>
</>
}
}
hooks结构中的setCounter(xxx)相当于class组件写法中setState({counter: xxx})
可以对比控制台看到,这样直接setCounter(setState)后立即输出的counter的是上一次的值,而按钮上显示正确,说明本次更新是异步的(react这样设计是为了批量更新而提高性能),打印时counter还没来得及改变。如果需要set完后立即取到counter的最新值,可以按如下方法实现同步的效果。
异步写成同步的方法
1. 写在setTimeout中
注意,只适用于class组件
add = () => {
setTimeout(()=>{
this.setState({counter:this.state.counter + 1})
console.log('~~this.state.counter',this.state.counter)
},0)
}
2. 合成事件使用原生事件替代
注意,只适用于class组件
// 原生事件
export default class Pre04SetStateSync extends React.Component {
state = {
counter: 0
}
componentDidMount() {
document.querySelector('#btn').addEventListener('click', this.add)
}
add = () => {
this.setState({counter: this.state.counter + 1})
console.log('~~this.state.counter', this.state.counter)
}
render() {
return <>
<h3>同步SetState</h3>
<p>请观察控制台</p>
<button id='btn'>counter: {this.state.counter}</button>
</>
}
}
3. 写入setState的回调函数中
注意,只适用于class组件
export default class Pre04SetStateSync extends React.Component {
state = {
counter: 0
}
add = () => {
this.setState({counter: this.state.counter + 1}, ()=>{
console.log('~~this.state.counter', this.state.counter)
})
}
render() {
return <>
<h3>同步SetState</h3>
<p>请观察控制台</p>
<button onClick={this.add}>counter: {this.state.counter}</button>
</>
}
}
4. 连续setState的问题
注意,class组件和hooks都可以
如果将add改为先加1再加2,会发现代码只执行了最后一个加2,加1被忽略了,如:
const add = () => {
setCounter(counter + 1)
setCounter(counter + 2)
}
解决方法是将setState的参数写成函数形式
const add = () => {
setCounter(counter => counter + 1)
setCounter(counter => counter + 2)
}
5. 使用副作用useEffect
注意,只适用于hooks
export default function Pre04SetStateSync() {
const [counter, setCounter] = useState(0)
const add = () => {
setCounter(counter + 1)
}
useEffect(() => {
console.log({counter})
}, [counter])
return <>
<h3>同步SetState</h3>
<p>请观察控制台</p>
<button onClick={add}>counter: {counter}</button>
</>
}
react hooks常用方法
1.useState
function Example01(){
const [ count, setCount ] = useState(0) //声明
return(
<div>
<p>{count}</p> //读取
<button onClick={()=>setCount(count+1)}>计数</button> // 使用(修改)
</div>
)
}
2.useEffect
1.React首次渲染和之后的每次渲染都会调用一遍useEffect函数,而之前我们要用两个生命周期函数分别表示首次渲染(componentDidMonut)和更新导致的重新渲染(componentDidUpdate)
2.useEffect中定义的函数的执行不会阻碍浏览器更新视图,也就是说这些函数时异步执行的,而componentDidMonut和componentDidUpdate中的代码都是同步执行的。
注意:
如果useEffect后面没有依赖:
这种时候每次每次页面更新都会执行
useEffect(()=>{
console.log('执行');
})
如果后面为空
页面初始的时候执行一次
useEffect(()=>{
console.log('执行');
},[])
如果后面有值且不为空
只有当count改变时才会被触发
useEffect(()=>{
console.log('执行');
},[count])
使用useEffect解绑,组件卸载的时候,比如需要清除计时器等:
但是当传空数组[]时,就是当组件将被销毁时才进行解绑,这也就实现了componentWillUnmount的生命周期函数。
function Index() {
useEffect(()=>{
console.log('useEffect=>Index')
return ()=>{
console.log('Index页面离开')
}
},[])
return <h2>测试解绑</h2>;
}
3.useContext上下文传值
1.父组件:
const CountContext = createContext() //引入
function Example01(){
const [ count, setCount ] = useState(0)
return(
<div>
<p>{count}</p>
<button onClick={()=>setCount(count+1)}>计数</button>
<CountContext.Provider value={count}> //使用包裹子组件传递值
<ChildContent/>
</CountContext.Provider>
</div>
)
}
2.子组件:
function ChildContent(){
const context = useContext(CountContext)
return(
<p>{context}</p>
)
}
4.useReducer
它也是React hooks提供的函数,可以增强我们的Reducer,实现类似Redux的功能。
import React, { useReducer } from 'react'
function Example5(){
const [ count, dispatch ] = useReducer((state,action)=>{
switch(action){ //通过判断对应的action,去执行对应的方法
case 'add':
return state+1
case 'sub':
return state-1
default:
return state
}
},1)
return(
<div>
<p>{count}</p>
<button onClick={()=>dispatch('add')}>add</button> //通过dispatch,传递对应的action,调用对应的方法
<button onClick={()=>dispatch('sub')}>sub</button>
</div>
)
}
export default Example5
5.useMemo
useMemo主要用来解决使用React hooks产生的无用渲染的性能问题。
只要使用useMemo,然后给她传递第二个参数,参数匹配成功,才会执行。
1.在父组件里面,传递对应需要的参数
import React , {useState,useMemo} from 'react';
function Example7(){
const [one , setOne] = useState('第一个的状态')
const [two , setTwo] = useState('志玲待客状态')
return (
<>
<button onClick={()=>{setOne(new Date().getTime())}}>第一个</button>
<button onClick={()=>{setTwo(new Date().getTime())}}>第二个</button>
<ChildComponent name={one}>{two}</ChildComponent>
</>
)
}
2.父组件调用子组件
function ChildComponent({name,children}){
function changeXiaohong(name){
return name
}
const actionXiaohong = useMemo(()=>changeXiaohong(name),[name])
return (
<>
<div>{actionXiaohong}</div>
<div>{children}</div>
</>
)
}
6.useRef
用useRef获取React JSX中的DOM元素,获取后你就可以控制DOM的任何东西了。但是一般不建议这样来作,React界面的变化可以通过状态来控制
import React, { useRef } from 'react'
function Example8(){
const inputRef = useRef(null)
const onButtonClick=()=>{
inputRef.current.value='THIS IS INPUT'
console.log(inputRef);
}
return(
<div>
<input type="text" ref={inputRef}/>
<button onClick = {onButtonClick}>显示</button>
</div>
)
}
export default Example8
保存普通变量
import React, { useRef,useState } from 'react'
function Example8(){
const inputRef = useRef(null)
const onButtonClick=()=>{
inputRef.current.value='THIS IS INPUT'
console.log(inputRef);
}
const [state, setstate] = useState('inputValue') //声明一个变量
return(
<div>
<input type="text" ref={inputRef}/>
<button onClick = {onButtonClick}>显示</button>
<input value={state} type="text" onChange={(e)=>setstate(e.target.value)}/> //绑定对应的值以及绑定onChange事件
</div>
)
}
export default Example8
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。