使用hook的好处:
1.可以不再使用class(有状态组件)
2.不用考虑复杂的react生命周期钩子函数
3.让this的处理变得简单
普通版本:
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
使用hooks的版本:
import { useState } from 'react';
function Example() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
import { useState } from 'react';
这一句引入了useState这个hook
const [count, setCount] = useState(0);
使用es6解构赋值,useState(0)的意思是给count赋予初始值0
count是一个状态值,setCount是给这个状态值进行更新的函数
如果不解构的话,上面的代码得写成这样⬇️
let _useState = useState(0);
let count = _useState[0];
let setCount = _useState[1];
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
在这里使用count 可以直接用,我们不需要写成{this.state.count}这样了。
当用户点击按钮时,我们调用setCount函数,这个函数接收的参数是修改过的新状态值。接下来的事情就交给react了,react将会重新渲染我们的Example组件,并且使用的是更新后的新的状态。
首先,useState是可以多次调用的,所以我们完全可以这样写:
function ExampleWithManyStates() {
const [age, setAge] = useState(42);
const [fruit, setFruit] = useState('banana');
const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
}
这个时候 useState根据调用的顺序执行
const [age, setAge] = useState(42);
这一句由两次渲染组成:
1.给age赋值为42
2.读取age(这时候传的参数42直接被忽略)
所以上面的多次调用可以变成这样:
//第一次渲染
useState(42); //将age初始化为42
useState('banana'); //将fruit初始化为banana
useState([{ text: 'Learn Hooks' }]); //...
//第二次渲染
useState(42); //读取状态变量age的值(这时候传的参数42直接被忽略)
useState('banana'); //读取状态变量fruit的值(这时候传的参数banana直接被忽略)
useState([{ text: 'Learn Hooks' }]); //...
这也就是为什么useState中不能使用if-else语句的原因了
使用使用if后 赋值和读取 可能会产生一个错位,导致程序错误
例如
let showFruit = true;
function ExampleWithManyStates() {
const [age, setAge] = useState(42);
if(showFruit) {
const [fruit, setFruit] = useState('banana');
showFruit = false;
}
const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
渲染结果会变成⬇️
//第一次渲染
useState(42); //将age初始化为42
useState('banana'); //将fruit初始化为banana
useState([{ text: 'Learn Hooks' }]); //...
//第二次渲染
useState(42); //读取状态变量age的值(这时候传的参数42直接被忽略)
// useState('banana');
useState([{ text: 'Learn Hooks' }]); //读取到的却是状态变量fruit的值,导致报错
react规定我们必须把hooks写在函数的最外层,不能写在if-else等条件语句当中,来确保hooks的执行顺序一致。
1. useState的初始值,只在第一次有效
下面代码里的data就不能动态赋值给name
const Child = memo(({data}) =>{
console.log('child render...', data)
const [name, setName] = useState(data)
return (
<div>
<div>child</div>
<div>{name} --- {data}</div>
</div>
);
})
const Hook =()=>{
console.log('Hook render...')
const [count, setCount] = useState(0)
const [name, setName] = useState('rose')
return(
<div>
<div>
{count}
</div>
<button onClick={()=>setCount(count+1)}>update count </button>
<button onClick={()=>setName('jack')}>update name </button>
<Child data={name}/>
</div>
)
}
React 假设当你多次调用 useState 的时候,你能保证每次渲染时它们的调用顺序是不变的。
通过在函数组件里调用它来给组件添加一些内部 state,React会在重复渲染时保留这个 state
useState 唯一的参数就是初始 state
useState 会返回一个数组:一个 state,一个更新 state 的函数