本文目录
第一个简单组件hello word
import React, { useContext } from 'react'
import { ThemeContext } from '../App'
interface IHelloProps {
message?: string;
}
const Hello: React.FC<IHelloProps> = (props) => {
const theme = useContext(ThemeContext)
console.log(theme)
const style = {
background: theme.background,
color: theme.color,
}
return <h2 style={style}>{props.message}</h2>
}
Hello.defaultProps = {
message: "Hello World"
}
export default Hello
1、hook
钩子是允许从功能组件(function component)“挂钩”React状态和生命周期功能的功能。钩子在类内部不起作用 - 它们允许你在没有类的情况下使用React。
useState简单实例
import { useState } from 'react';
function Example() {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
1-1、useEffect
Effect Hook中的useEffect增加了在功能组件执行副作用的功能。它与React类中的componentDidMount,componentDidUpdate和componentWillUnmount具有相同的用途,但统一为单个API。
简单实例:
import React, { useState, useEffect } from 'react'
const MouseTracker: React.FC = () => {
const [ positions, setPositions ] = useState({x: 0, y: 0})
useEffect(() => {
console.log('add effect', positions.x)
const updateMouse= (e: MouseEvent) => {
console.log('inner')
setPositions({ x: e.clientX, y: e.clientY })
}
document.addEventListener('click', updateMouse)
return () => {
console.log('remove effect', positions.x)
document.removeEventListener('click', updateMouse)
}
}, [])
console.log('before render', positions.x)
return (
<p>X: {positions.x}, Y : {positions.y}</p>
)
}
export default MouseTracker
useEffect不过不传递第二个参数在页面每次重新渲染时都会调用,这里第二个参数传入空数组的意思是只有在页面出现或者卸载时执行.如果传入其他变量则执行与否只依赖该变量是否变化.
不同组件之间共享hook封装
import React, { useState, useEffect } from 'react'
const useMousePosition = () => {
const [ positions, setPositions ] = useState({x: 0, y: 0})
useEffect(() => {
console.log('add effect', positions.x)
const updateMouse= (e: MouseEvent) => {
setPositions({ x: e.clientX, y: e.clientY })
}
document.addEventListener('mousemove', updateMouse)
return () => {
console.log('remove effect', positions.x)
document.removeEventListener('mousemove', updateMouse)
}
}, [])
return positions
}
export default useMousePosition
定义后在其他组件中引入就可共用状态
const positons = useMousePosition();
自定义hook
在react hook中我们可以把一些天然逻辑重复的业务抽离出来,下面看下例子:
定义文件useURLLoader.tsx
import { useState, useEffect } from 'react'
import axios from 'axios'
const useURLLoader = (url: string, deps: any[] = []) => {
const [data, setData] = useState<any>(null)
const [loading, setLoading] = useState(false)
useEffect(() => {
setLoading(true)
axios.get(url).then(result => {
setData(result.data)
setLoading(false)
})
}, deps)
return [data, loading]
}
export default useURLLoader
使用
interface IShowResult {
message: string;
status: string;
}
const App: React.FC = () => {
const [show, setShow] = userState(true)
const [data, loadin] = userState(true) = useURLLoader('https://dog.ceo/api/breeds/imagte', show)
const dogResult = data as IShowResult
return (
<div>
<button oClick={() => {
setShow(!show)
}}>
Refresh dog photo
</button>
{loading ? <p>读取中</p> : <imag src={dogResult && dogResult.message} />}
</div>
)
}
1-2、useRef与useContext
App.tsx文件
import React, { useState } from 'react';
import './App.css';
import LikeButton from './components/LikeButton'
interface IThemeProps {
[key: string]: {color: string; background: string;}
}
const themes: IThemeProps = {
'light': {
color: '#000',
background: '#eee',
},
'dark': {
color: '#fff',
background: '#222',
}
}
export const ThemeContext = React.createContext(themes.light)
const App: React.FC = () => {
const [ show, setShow ] = useState(true)
return (
<div className="App">
<ThemeContext.Provider value={themes.dark}>
<header className="App-header">
<LikeButton />
</header>
</ThemeContext.Provider>
</div>
);
}
export default App;
LikeButton.tsx文件
import React, { useState, useEffect, useRef, useContext } from 'react'
import { ThemeContext } from '../App'
const LikeButton: React.FC = () => {
const [like, setLike] = useState(0)
const likeRef = useRef(0)
const didMountRef = useRef(false)
const domRef = useRef<HTMLInputElement>(null)
const theme = useContext(ThemeContext)
console.log(theme)
const style = {
background: theme.background,
color: theme.color,
}
useEffect(() => {
console.log('document title effect is running')
document.title = `点击了${like}次`
}, [like])
useEffect(() => {
if (didMountRef.current) {
console.log('this is updated')
} else {
didMountRef.current = true
}
})
useEffect(() => {
if (domRef && domRef.current) {
domRef.current.focus()
}
})
function handleAlertClick() {
setTimeout(() => {
alert('you clicked on ' + likeRef.current)
}, 3000)
}
return (
<>
<input type="text" ref={domRef} />
<button style={style} onClick={() => {setLike(like + 1); likeRef.current++}}>
{like} 👍
</button>
<button onClick={handleAlertClick}> Alert!
</button>
</>
)
}
export default LikeButton
1-3、 forwardRef
引用传递(Ref forwading)是一种通过组件向子组件自动传递 引用ref 的技术。
import React, { Component, createRef, forwardRef } from 'react';
const FocusInput = forwardRef((props, ref) => (
<input type="text" ref={ref} />
));
class ForwardRef extends Component {
constructor(props) {
super(props);
this.ref = createRef();
}
componentDidMount() {
const { current } = this.ref;
current.focus();
}
render() {
return (
<div>
<p>forward ref</p>
<FocusInput ref={this.ref} />
</div>
);
}
}
export default ForwardRef;
1-4、useRef
const refContainer = useRef(initialValue);
useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内持续存在。
一个常见的用例便是命令式地访问子组件:
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` 指向已挂载到 DOM 上的文本输入元素
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
useRef和createRef的区别
react中useState、useRef、变量之间的区别
1-5、useRequest
import { useRequest } from '@umijs/hooks';
function getUsername() {
return Promise.resolve('jack');
}
export default () => {
const { data, error, loading } = useRequest(getUsername)
if (error) return <div>failed to load</div>
if (loading) return <div>loading...</div>
return <div>Username: {data}</div>
}
这是一个最简单的网络请求示例。在这个例子中 useRequest 接收了一个 Promise 函数。在组件初始化时,会自动触发 getUsername 执行,并自动管理 data 、 loading 、 error 等数据,我们只需要根据状态来写相应的 UI 实现即可。
useRequest教程
1-6、useCreation
1、确定输入输出,useCreation接受两个参数,一个工厂函数,一个依赖项数组,并返回工厂函数执行后的结果
1-7、useMemo和 useCallback
一篇文章带你理解 React 中最“臭名昭著”的 useMemo 和 useCallback
2、组件之间的传值
参考
父组件
import { useCallback, useEffect, useState, useRef } from "react";
import Header from "../../components/header/index";
import Footer from "../../components/footer/index";
import Changefather from "./components/changefather";
const Home = () => {
const [sisters, setsisters] = useState("村里一朵花");
const [loding, setloding] = useState(false); //loding;
const [childData, setChildData]: any = useState(); //获取子组件的值
const childMethodRef:any = useRef();
const changeloding = () => {
setloding(true);
setTimeout(() => {
setloding(false);
}, 1000);
};
const handleChildFun = () => {
childMethodRef.current.fun2()
};
const getchildfn = useCallback((data: any) => {
setChildData(data);
}, []);
return (
<div className="home">
<div className="home_div">
<Header headeractive={1}></Header>
<Changefather
sisters={sisters}
setsisters={setsisters}
handleChildData={getchildfn}
cRef={childMethodRef}
></Changefather>
<div className="buttondiv">
<span>这是一个小小的button</span>
<div className="lodingdiv" style={loding ? {} : { display: "none" }}>
<div className="loding"></div>
</div>
</div>
<button
onClick={() => {
changeloding();
}}
>
changeloding
</button>
{<div>这是子组件的值{childData}</div>}
<input type="number" placeholder="555" />
</div>
<div
onClick={() => {
handleChildFun();
}}
>
我要
</div>
<Footer></Footer>
</div>
);
};
export default Home;
子组件
import{ useEffect, useState ,useImperativeHandle,forwardRef} from "react";
import Countdown from "react-countdown";
import dayjs from "dayjs";
interface sister {
sisters: string;
setsisters: any;
handleChildData:any;
cRef:any
}
let Changeyears = (props: sister):any => {
const { sisters, setsisters,handleChildData,cRef } = props;
const [Cdtime,setCdtime]=useState(dayjs(1649999957832).valueOf())
const [childtext , setchildtext ] = useState('')
useImperativeHandle(cRef, () => ({
childFun (info: any) {
console.log(info)
},
fun2(){
console.log('fun2')
}
}));
useEffect(()=>{
handleChildData(childtext)
},[childtext])
return (
<>
<Countdown date={Cdtime}
renderer={time => {
const {days,hours,minutes,seconds} = time.formatted
return (
<div>
还有{days}天{hours}时{minutes}分{seconds}秒
</div>
)
}}
/>
<div onClick={()=>{
setchildtext('今天给爸爸洗脚')
}}>传给父组件值</div>
<div onClick={()=>{
setchildtext('今天不给爸爸洗脚')
}}> 第二次传给父组件的值</div>
<div className="animate__flash">{sisters}</div>
<button onClick={() => setsisters("老太婆")}>时间的变迁</button>
</>
);
};
Changeyears = forwardRef(Changeyears);
export default Changeyears;
import React, { useRef, useImperativeHandle } from 'react';
import ReactDOM from 'react-dom';
const FancyInput = React.forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} type="text" />
});
const App = props => {
const fancyInputRef = useRef();
return (
<div>
<FancyInput ref={fancyInputRef} />
<button
onClick={() => fancyInputRef.current.focus()}
>父组件调用子组件的 focus</button>
</div>
)
}
ReactDOM.render(<App />, root);
3、自定义hook实现
import React,{Component,useState} from 'react'
function useCountFather(initValue){
var [count,setCount]=useState(initValue)
function increase(){
setCount(++count)
}
function decrease(){
setCount(--count)
}
return [count,{increase,decrease}]
}
function Count(){
var [count,countFatherApi]=useCountFather(0)
return(
<div>
<p>{count}</p>
<button onClick={()=>{countFatherApi.increase()}}>Increase</button>
<button onClick={()=>{countFatherApi.decrease()}}>Decrease</button>
</div>
)
}
function App(){
return(
<div>
<Count></Count>
</div>
)
}
export default App;
4、hook中网络请求数据
import React, { useState, useEffect } from 'react';
import axios from 'axios';
function App() {
const [data, setData] = useState({ hits: [] });
useEffect(async () => {
const result = await axios(
'https://hn.algolia.com/api/v1/search?query=redux',
);
setData(result.data);
});
return (
<ul>
{data.hits.map(item => (
<li key={item.objectID}>
<a href={item.url}>{item.title}</a>
</li>
))}
</ul>
);
}
export default App;
手动触发
function App() {
const [data, setData] = useState({ hits: [] });
const [query, setQuery] = useState('redux');
const [search, setSearch] = useState('');
useEffect(() => {
const fetchData = async () => {
const result = await axios(
`http://hn.algolia.com/api/v1/search?query=${query}`,
);
setData(result.data);
};
fetchData();
}, [query]);
return (
<Fragment>
<input
type="text"
value={query}
onChange={event => setQuery(event.target.value)}
/>
<button type="button" onClick={() => setSearch(query)}>
Search
</button>
<ul>
{data.hits.map(item => (
<li key={item.objectID}>
<a href={item.url}>{item.title}</a>
</li>
))}
</ul>
</Fragment>
);
}