this
const [state, setState] = useState(initialState);
import React,{useState} from 'react';
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
number: 0
};
}
render() {
return (
<div>
<p>{this.state.number}</p>
<button onClick={() => this.setState({ number: this.state.number + 1 })}>
+
</button>
</div>
);
}
}
function Counter2(){
const [number,setNumber] = useState(0);
return (
<>
<p>{number}</p>
<button onClick={()=>setNumber(number+1)}>+</button>
</>
)
}
export default Counter2;
function Counter2(){
const [number,setNumber] = useState(0);
function alertNumber(){
setTimeout(()=>{
alert(number);
},3000);
}
return (
<>
<p>{number}</p>
<button onClick={()=>setNumber(number+1)}>+</button>
<button onClick={alertNumber}>alertNumber</button>
</>
)
}
function Counter2(){
const [number,setNumber] = useState(0);
let numberRef = useRef(number);
numberRef.current = number;
function alertNumber(){
setTimeout(()=>{
alert(numberRef.current);
},3000);
}
+ function lazy(){
+ setTimeout(()=>{
+ setNumber(number+1);
+ },3000);
+ }
+ function lazyFunc(){
+ setTimeout(()=>{
+ setNumber(number=>number+1);
+ },3000);
+ }
return (
<>
<p>{number}</p>
<button onClick={()=>setNumber(number+1)}>+</button>
<button onClick={lazy}>lazy+</button>
<button onClick={lazyFunc}>lazyFunc+</button>
<button onClick={alertNumber}>alertNumber</button>
</>
)
}
function Counter3(){
const [{name,number},setValue] = useState(()=>{
return {name:'计数器',number:0};
});
return (
<>
<p>{name}:{number}</p>
<button onClick={()=>setValue({number:number+1})}>+</button>
</>
)
}
function Counter4(){
const [counter,setCounter] = useState({name:'计数器',number:0});
console.log('render Counter')
return (
<>
<p>{counter.name}:{counter.number}</p>
<button onClick={()=>setCounter({...counter,number:counter.number+1})}>+</button>
<button onClick={()=>setCounter(counter)}>-</button>
</>
)
}
useCallback
,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新useMemo
,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算function Child({onButtonClick,data}){
console.log('Child render');
return (
<button onClick={onButtonClick} >{data.number}</button>
)
}
Child = memo(Child);
function App(){
const [number,setNumber] = useState(0);
const [name,setName] = useState('zhufeng');
const addClick = useCallback(()=>setNumber(number+1),[number]);
const data = useMemo(()=>({number}),[number]);
return (
<div>
<input type="text" value={name} onChange={e=>setName(e.target.value)}/>
<Child onButtonClick={addClick} data={data}/>
</div>
)
}
const [state, dispatch] = useReducer(reducer, initialArg, init);
const initialState = 0;
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {number: state.number + 1};
case 'decrement':
return {number: state.number - 1};
default:
throw new Error();
}
}
function init(initialState){
return {number:initialState};
}
function Counter(){
const [state, dispatch] = useReducer(reducer, initialState,init);
return (
<>
Count: {state.number}
<button onClick={() => dispatch({type: 'increment'})}>+</button>
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
</>
)
}
static contextType = MyContext
或者 <MyContext.Consumer>
const CounterContext = React.createContext();
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {number: state.number + 1};
case 'decrement':
return {number: state.number - 1};
default:
throw new Error();
}
}
function Counter(){
let {state,dispatch} = useContext(CounterContext);
return (
<>
<p>{state.number}</p>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
</>
)
}
function App(){
const [state, dispatch] = useReducer(reducer, {number:0});
return (
<CounterContext.Provider value={{state,dispatch}}>
<Counter/>
</CounterContext.Provider>
)
}
componentDidMount
、componentDidUpdate
和 componentWillUnmount
具有相同的用途,只不过被合并成了一个 APIuseEffect(didUpdate);
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
number: 0
};
}
componentDidMount() {
document.title = `你点击了${this.state.number}次`;
}
componentDidUpdate() {
document.title = `你点击了${this.state.number}次`;
}
render() {
return (
<div>
<p>{this.state.number}</p>
<button onClick={() => this.setState({ number: this.state.number + 1 })}>
+
</button>
</div>
);
}
}
在这个 class 中,我们需要在两个生命周期函数中编写重复的代码,这是因为很多情况下,我们希望在组件加载和更新时执行同样的操作。我们希望它在每次渲染之后执行,但 React 的 class 组件没有提供这样的方法。即使我们提取出一个方法,我们还是要在两个地方调用它。useEffect会在第一次渲染之后和每次更新之后都会执行
import React,{Component,useState,useEffect} from 'react';
import ReactDOM from 'react-dom';
function Counter(){
const [number,setNumber] = useState(0);
// 相当于 componentDidMount 和 componentDidUpdate:
useEffect(() => {
// 使用浏览器的 API 更新页面标题
document.title = `你点击了${number}次`;
});
return (
<>
<p>{number}</p>
<button onClick={()=>setNumber(number+1)}>+</button>
</>
)
}
ReactDOM.render(<Counter />, document.getElementById('root'));
每次我们重新渲染,都会生成新的 effect,替换掉之前的。某种意义上讲,effect 更像是渲染结果的一部分 —— 每个 effect 属于一次特定的渲染。
function Counter(){
const [number,setNumber] = useState(0);
// 相当于componentDidMount 和 componentDidUpdate
useEffect(() => {
console.log('开启一个新的定时器')
const $timer = setInterval(()=>{
setNumber(number=>number+1);
},1000);
return ()=>{
console.log('销毁老的定时器');
clearInterval($timer);
}
});
return (
<>
<p>{number}</p>
</>
)
}
function Counter(){
const [number,setNumber] = useState(0);
// 相当于componentDidMount 和 componentDidUpdate
useEffect(() => {
console.log('开启一个新的定时器')
const $timer = setInterval(()=>{
setNumber(number=>number+1);
},1000);
},[]);
return (
<>
<p>{number}</p>
</>
)
}
.current
属性被初始化为传入的参数(initialValue)const refContainer = useRef(initialValue);
import React, { useState, useEffect, useRef } from 'react';
import ReactDOM from 'react-dom';
function Parent() {
let [number, setNumber] = useState(0);
return (
<>
<Child />
<button onClick={() => setNumber({ number: number + 1 })}>+</button>
</>
)
}
let input;
function Child() {
const inputRef = useRef();
console.log('input===inputRef', input === inputRef);
input = inputRef;
function getFocus() {
inputRef.current.focus();
}
return (
<>
<input type="text" ref={inputRef} />
<button onClick={getFocus}>获得焦点</button>
</>
)
}
ReactDOM.render(<Parent />, document.getElementById('root'));
function Child(props,ref){
return (
<input type="text" ref={ref}/>
)
}
Child = forwardRef(Child);
function Parent(){
let [number,setNumber] = useState(0);
const inputRef = useRef();
function getFocus(){
inputRef.current.value = 'focus';
inputRef.current.focus();
}
return (
<>
<Child ref={inputRef}/>
<button onClick={()=>setNumber({number:number+1})}>+</button>
<button onClick={getFocus}>获得焦点</button>
</>
)
}
useImperativeHandle
可以让你在使用 ref 时自定义暴露给父组件的实例值function Child(props,ref){
const inputRef = useRef();
useImperativeHandle(ref,()=>(
{
focus(){
inputRef.current.focus();
}
}
));
return (
<input type="text" ref={inputRef}/>
)
}
Child = forwardRef(Child);
function Parent(){
let [number,setNumber] = useState(0);
const inputRef = useRef();
function getFocus(){
console.log(inputRef.current);
inputRef.current.value = 'focus';
inputRef.current.focus();
}
return (
<>
<Child ref={inputRef}/>
<button onClick={()=>setNumber({number:number+1})}>+</button>
<button onClick={getFocus}>获得焦点</button>
</>
)
}
function LayoutEffect() {
const [color, setColor] = useState('red');
useLayoutEffect(() => {
alert(color);
});
useEffect(() => {
console.log('color', color);
});
return (
<>
<div id="myDiv" style={{ background: color }}>颜色</div>
<button onClick={() => setColor('red')}>红</button>
<button onClick={() => setColor('yellow')}>黄</button>
<button onClick={() => setColor('blue')}>蓝</button>
</>
);
}
function useNumber(){
const [number,setNumber] = useState(0);
useEffect(() => {
console.log('开启一个新的定时器')
const $timer = setInterval(()=>{
setNumber(number+1);
},1000);
return ()=>{
console.log('销毁老的定时器')
clearInterval($timer);
}
});
return number;
}
function Counter1(){
let number1 = useNumber();
return (
<>
<p>{number1}</p>
</>
)
}
function Counter2(){
let number = useNumber();
return (
<>
<p>{number}</p>
</>
)
}
function App(){
return <><Counter1/><Counter2/></>
}