自定义React hooks
回顾一下React常用hooks
React hooks中除了常用的useState
、useEffect
、useRef
。
我们还可以自定义hooks
,可以达到不增加组件而实现组件之间的一些复用的目的。
在子组件中,可以获取父级传来的值,也可以对值进行修改。
子组件Child.js
import React, { useState, useEffect, useRef } from 'react';
export default function Child(props) {
let { data } = props;//接收父组件传来的数据
//只要不修改ref,就会存储初始值(变化之前的值)
let [age, setAge] = useState(0);
//绑定dom
//let currentAge = useRef();
//下面的代码是将每次变化后的age值,传入useRef(),
//这样一来就只是对数据进行操作,绑定的是数据而不是具体的dom了
let currentAge = useRef(age);
useEffect(() => {
// 绑定的dom
//点击按钮“长一岁”,此时控制台输出的是绑定的标签及其包含的内容
//控制台输出如下:
// <h2>0</h2>
// <h2>1</h2>
// ......
console.log(currentAge.current);
// currentAge.current初始值, age是存变化后的值
console.log(currentAge.current, age);
// 把每次变化后的age值,再赋给当前值curAge.current,即变化前的值
currentAge.current = age;
// 绑定了数据,不再是dom
// 每次变化后的值赋值给了当前值,此时点击按钮“长一岁”时控制台输出内容都是数据,而不是标签了
// 0
// 0 1
// 1
// 1 2
// 2
// ...
}, [age]);
let [txt, setTxt] = useState("today is sunny");
let txtAfter = useRef(txt);
useEffect(() => {
console.log(txtAfter.current,txt);//txt即是每次变化的值
txtAfter.current = txt;
console.log(txtAfter);
}, [txt]);
return (
<div>
<h2>name:{data.name}</h2>
<h2 ref={currentAge}>age:{age}</h2>
<button onClick={() => { setAge(++age) }}>长一岁</button>
<p>{txt}</p>
<input type="text" value={txt}
onChange={({ target }) => { setTxt(target.value) }} />
</div>
);
}
父组件App.js
import React, { useState, useEffect } from 'react';
import Child from './Child';
export default function App() {
let [data, setData] = useState({
name: "金毛",
age: 3
})
let [show, setShow] = useState(true);
return (
<div>
{show?<Child data={data} />:""}
<button onClick={() => {
setData({
// 修改name值,age不变
name: "泰迪",
age: data.age
})
}}>
点击切换
</button>
<button onClick={()=>{setShow({show:false})}}>
卸载
</button>
</div>
);
}
自定义hooks需注意
- 以use开头,遵循驼峰命名法
- 自定义hooks必须在React函数组件内调用
示例2
App.js
import React, { useEffect,useRef} from 'react';
import { useSize, useScrollY } from './myhooks'
export default function App() {
let [scrollY,setScrollY] = useScrollY();//组件内使用useScrollY,必须在React函数组件内调用
let newScrollY = useRef(scrollY);//绑定input框输入的数据
// 监测鼠标滚动距离
useEffect(()=>{
window.onscroll=()=>{
newScrollY.current = scrollY;//将每次改变的值赋给当前值,即滚动的最新值
setScrollY(newScrollY.current);
}
return ()=>{
window.onscroll = null;
}
},[scrollY]);
return (
<div>
<ul>
{
// 测试数据
[...(".".repeat(100))].map((item, index) => {
return <li key={index}>第{index + 1}条数据</li>
})
}
</ul>
<a onClick={() => {
// setScrollY(100); //调用此函数,点击跳到scrollY为100的位置
setScrollY(scrollY); //有input框输入的数值传入,如果想跳到哪个位置,直接输入对应的数值即可
}}
style={{position:'fixed',left:'200px',top:'200px'}}>
{scrollY}
</a>
{/* 添加一个input输入框,每次输入一个数值 */}
<input type="text" value={scrollY} ref={newScrollY}
onChange={({target})=>{setScrollY(target.value)}}
style={{position:'fixed',left:'200px',top:'220px'}}
/>
</div>
);
}
myhooks.js
import React, { useState } from 'react';
// 自定义hooks
// 开头必须是use
function useSize() {
return {
w:window.innerWidth,
h:window.innerHeight
}
}
function useScrollY() {//获取和设置滚动条
let [scrollY, setScrollY] = useState(window.scrollY);
return [
scrollY, //返回的值
(newScrollY)=>{ //修改这个值的函数
window.scrollTo(0,newScrollY);
setScrollY(newScrollY);
}
]
}
export {useSize,useScrollY};