朋也的博客 » 首页 » 文章
作者:朋也
日期:2019-07-23
类别:react.js学习笔记
版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
react又折腾出了个新玩意
react hooks
,虽然是很早之间就发布了,最近了解了一下这货是干啥的,总结一下
react hooks 这货是什么?
说白了,就是拿function
当组件用,因为之间用react定义组件用的是class
关键字,人家嫌麻烦,代码量太大,就折腾了这货,直接一个 function 就是一个组件。。
那么,原来用 class 定义的组件里可以写state,有生命周期,这货一个function怎么实现那些功能呢?
下面就来介绍一下人家是怎么在function里处理state和生命周期的
这个hook就是state,从它里面可以声明组件里要用到的state,举个例子
class写法
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
render() {
return <div>{count}</div>;
}
}
hook 写法
function Example() {
const [count, setCount] = useState(0);
return <div>{count}</div>
}
简单吧,声明一个state,就要附带着一个 setXXX ,这就相当于 setState()
, 比如这里声明的是 count
那么想更新值就要声明一个 setCount
变量(它也是一个方法),通过 setCount(1);
更新count的值后,组件就会重新渲染
useState()
方法中的参数是默认值的意思,上面count我想让它是个int类型的值,就给了个默认值为0,这次声明了个data,我想让它是个数组,就给了个[]
更新state,如下例子
function Example() {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount(count + 1)}>clicked {count}</button>
</div>
);
}
当然如果不想直接在onClick事件里调用 setCount 方法,想自定义方法来更新count的值,也可以在这个function组件里再定义一个方法来处理
function Example() {
const [count, setCount] = useState(0);
const updateCount = function() {
setCount(count + 1);
};
return (
<div>
<button onClick={() => updateCount()}>clicked {count}</button>
</div>
);
}
怎么在useState里声明多个变量呢?
function Example() {
const [state, setState] = useState({
count: 0,
data: [1, 2, 3]
});
const updateCount = function() {
setState({ ...state, count: state.count + 1 });
};
return (
<div>
<ul>
{state.data.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
<button onClick={() => updateCount()}>clicked {state.count}</button>
</div>
);
}
除了从 useState 里声明state外,还可以用另一个hook useReducer
,用法类似于 redux 里的 reducer
function Example() {
const [count, dispatch] = useReducer((count, { type, action }) => {
switch (type) {
case "update":
return action.payload;
default:
break;
}
}, 0);
return (
<div>
<button
onClick={() =>
dispatch({ type: "update", action: { payload: count + 1 } })
}
>
clicked {count}
</button>
</div>
);
}
相同的 useReducer 最后一个参数也是默认值, 通过dispatch方法传入类型然后修改state
链接文原: https://atjiu.github.io/2019/07/23/react-hooks/
那么如何在 useReducer 里声明多个变量呢?
function Example() {
const [state, dispatch] = useReducer(
(state, { type, action }) => {
switch (type) {
case "update":
return { ...state, count: state.count + 1 };
case "add":
return { ...state, data: [...state.data, action.payload + 1] };
default:
break;
}
},
{ count: 0, data: [1, 2, 3] }
);
return (
<div>
<ul>
{state.data.map(item => (
<li key={item}>{item}</li>
))}
</ul>
<button onClick={() => dispatch({ type: "update" })}>
clicked {state.count}
</button>
<button
onClick={() =>
dispatch({ type: "add", action: { payload: state.data.length } })
}
>
add
</button>
</div>
);
}
开发过react组件的人都知道,react组件里有很多生命周期,这些生命周期在 function 组件里是怎么实现的呢?这时就要用到 useEffect
了
首先是 componentDidMount
和 componentDidUpdate
两个生命周期,它俩在function组件里的实现如下
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("hello world");
});
return (
<div>
<button onClick={() => setCount(count + 1)}>clicked {count}</button>
</div>
);
}
上面代码运行后,可以看到浏览器的console里会打印出 hello world
这个打印就相当于是 componentDidMount
被执行了
点击button,count每次都会变化,也就是说state一直在变,然后会发现浏览器的 console 里会随着button点击后count变化也会打印 hello world
这时候就相当于 componentDidUpdate
在执行,每次state有变动的时候,useEffect
都会执行一次
那有没有办法不让它执行呢?有!
useEffect
有两个参数,第一个参数是个函数,第二个参数相当于条件,看一下面的例子
function Example() {
const [state, setState] = useState({ count: 0, data: [1, 2, 3] });
useEffect(() => {
console.log("hello world");
}, [state.count]);
return (
<div>
<ul>
{state.data.map(item => (
<li key={item}>{item}</li>
))}
</ul>
<button onClick={() => setState({ ...state, count: state.count + 1 })}>
clicked {state.count}
</button>
<button onClick={() => setState({ ...state, data: [...state.data, state.data.length + 1] })}>add</button>
</div>
);
}
当页面渲染完后,浏览器console里会有一个 hello world
输出,可以看见我在 useEffect
的第二个参数上加了个参数 state.count
这时候它就会以 state.count
为校验目标,只有当 state中的count有变化时,useEffect 里的第一个参数(函数)才会执行
也就是说当点击第二个按钮的时候,state更新的只是data变量,count变量没有变化,useEffect里的第一个函数参数就不会执行,这第二个参数也就相当于是 shouldComponentUpdate
这个生命周期了
最后再说一下组件卸载时的生命周期 componentWillUnmount
, 要在function组件里实现这个功能也很简单,只需要在 useEffect
里返回一个函数就可以了
function Example() {
const [show, setShow] = useState(false);
return (
<div className="App">
{show ? null : <Item />}
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button onClick={() => setShow(!show)}>show/hidden</button>
</div>
);
}
function Item() {
useEffect(() => {
console.log("子组件加载");
// 返回的函数名无所谓,可以随便起
return function bye() {
console.log("子组件卸载");
};
// return () => { // 可以写成匿名函数
// console.log("子组件卸载");
// };
});
return <div>我是子组件</div>;
}
当点击按钮时,子组件会交替的显示和不显示,也就意味着子组件在交替的加载和卸载,在浏览器的console里就可以看到 子组件加载
和 子组件卸载
的日志
function组件里父子组件传值很简单,因为它本身就是 function,所以传的值就是方法的参数,如下
function App() {
const [data, setData] = useState([1, 2, 3]);
return (
<div className="App">
<Item items={data} />
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button onClick={() => setData([...data, data.length + 1])}>add</button>
</div>
);
}
function Item({ items }) {
useEffect(() => {
console.log("子组件加载");
// 返回的函数名无所谓,可以随便起
return function bye() {
console.log("子组件卸载");
};
// return () => { // 可以写成匿名函数
// console.log("子组件卸载");
// };
});
return (
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
}