React
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, inital-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="/main.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
index.js
import React from 'react'
import ReactDOM from 'react-dom'
//这两个导入的时候必须用这样的接收名称
const myElement = React.createElement('h1',{ id: 'myElement',title: 'this is a element'},'someone')
const myBigElement = React.createElement('div',{ id: 'myBigElement',title: 'this is a big element'},'somebigone', myElement)
ReactDOM.render(myBigElement,document.getElementById('app'))
纯函数组件
无状态组件可以通过减少继承Component而来的生命周期函数而达到性能优化的效果。从本质上来说,无状态组件就是一个单纯的render函数,所以无状态组件的缺点也是显而易见的。因为它没有shouldComponentUpdate生命周期函数,所以每次state更新,它都会重新绘制render函数。所以进一步
这里是个计数器Counter:
import React,{useState} from 'react';
import ReactDOM from 'react-dom';
function Counter(){
const[num , setNum] = useState(0);
const click () => setNum(num + 1);
return (<button onClick={click}>{num}</button>);
}
Memo
上面已经说到纯函数的组件将导致组件的重复渲染行为,进而造成好不容易优化出的性能,又被一定程度上打了折扣,这个时候我们需要Memo,Memo用来优化函数组件的重复渲染行为,当传入属性值都不变的情况下不会触发组件的重新渲染,否则就会触发组件的重新渲染。
用法
import React from "react";
import ReactDOM from 'react-dom';
function Counter(){
const[num , setNum] = useState(0);
const click () => setNum(num + 1);
return (<button onClick={click}>{num}</button>);
}
export default React.memo(Counter,isEqual)//第二个参数是渲染对比的自定义参数,默认情况下其只会对复杂对象做浅层对比,如果你想要控制对比过程,那么请将自定义的比较函数通过第二个参数传入来实现
Hooks API(钩子函数)
Hook是React 16.8(包括react-dom 16.8)新增的特性,它可以让你在不编写class的情况下使用state及其它的React特性,Hook是一个特殊的函数。
useState
通过在函数组件里调用useState
来给组件添加一下内部的state
。
const [data,修改data的函数]=useState(data初始化的值);
import React,{useState} from 'react';
import ReactDOM from 'react-dom';
function Counter(){
const[num , setNum] = useState(0);
const click () => setNum(num + 1);
return (<button onClick={click}>{num}</button>);
}
//如果要修改状态的函数类似class组件的this.setState
function Test(){
const[person , setObj] = useState({name:'lqq' , age:18});
const click = () => setObj({ ...obj , age: obj.age + 1});//一定要解构出来,不然改不了值
return(
<>
<p>{obj.name}</p>
<button onClick={click}>{obj.age}</button>
</>
);
}
原理
let memoizedState;
function useState (initialState) {
memoizedState = memoizedState || initialState
function setState (newState) {
memoizedState = newState
render()
}
return [memoizedState, setState]
}
useEffect
useEffect在函数组件中执行副作用(钩子函数)的操作。
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://localhost/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>
);
}
什么是副作用?
除了修改外部的变量,一个函数在执行过程中还有很多方式产生外部可观察的变化,比如说调用 DOM API 修改页面,或者你发送了 Ajax 请求,还有调用 window.reload 刷新浏览器,甚至是 console.log 往控制台打印数据也是副作用。
function Counter(){
const[num , setNum] = useState(0);
const saveCurrent = useRef();
const click = () => {
setNum(num + 1);
saveCurrent.current = num + 1;
};
const alertHandle = () =>{
// 3秒延迟以后打印最新的值
setTimeout(() => {
console.log(saveCurrent.current);
}, 3000);
};
return (
<>
<p>{num}</p>
<button onClick={click}>click</button>
<button onClick={alertHandle}>alert</button>
</>
);
}
useMemo
useMemo是针对一个函数,是否多次执行,避免无用方法的调用,以此来节省性能损耗,他会返回一个该函数的值,也就是调用函数并返回其结果
function Button({ name, children }) {
function changeName(name) {
console.log('11')
return name + '改变name的方法'
}
const otherName = useMemo(()=>changeName(name),[name])//这样子做就不会因为改变其他非name的变量而调用changeName()
return (
<>
<div>{otherName}</div>
<div>{children}</div>
</>
)
}
export default Button
useCallback
useCallback针对一个函数,并返回该回调函数,他将返回函数本身,只有依赖发生变化时,才会调用
//有一个父组件,其中包含子组件,子组件接收一个函数作为 props ;通常而言,如果父组件更新了,子组件也会执行更新;但是大多数场景下,更新是没有必要的,我们可以借助 useCallback 来返回函数,然后把这个函数作为 props 传递给子组件;这样,子组件就能避免不必要的更新。这个例子中count变动时会重新选仍然子组件,但val变动时不会
function Parent() {
const [count, setCount] = useState(1);
const [val, setValue] = useState('');
const getNum = useCallback(() => {
return Array.from({length: count * 100}, (v, i) => i).reduce((a, b) => a+b)
}, [count])
return <div>
<Child getNum={getNum} />
<div>
<button onClick={() => setCount(count + 1)}>+1</button>
<input value={val} onChange={event => setValue(event.target.value)}/>
</div>
</div>;
}
const Child = React.memo(function ({ getNum }: any) {
return <h4>总和:{getNum()}</h4>
})
useContext
组件之间共享状态,可以使用useContext()。
1.首先要进行导入createContext,useContext
import React,{useState,createContext,useContext} from 'react'
function Child(){
//在子组件中使用useContext进行接收父组件传递的上下文,这样值就能传递过来了
const count1=useContext(CountContext)
return (
<h1>{count1}</h1>
)
}
const CountContext=createContext()//首先创建一个上下文全局变量
function Example3(){
const [count,setCount]=useState(0)
function handleClick(){
setCount(count+1)
}
return (
<div>
点击{count}
<button onClick={handleClick}>clickme</button>
其次是作为父组件将值传递过去,Provider 相当于提供者,Child是子组件
<CountContext.Provider value={count}>
<Child></Child>
</CountContext.Provider>
</div>
)
}
export default Example3
useRef
useRef返回的是一个可变的ref对象,它的属性current被初始化为传入的参数(initialValue),返回的ref对象在组件的整个生命周期内保持不变
function TextInputWithFocusButton() {
const inputEl = useRef();
const getValue = () => {
// `current` 指向已挂载到 DOM 上的文本输入元素
console.log(inputRef.current.value)
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={getValue}>获取input的值</button>
</>
);
}
useQuery
function List(){
const { data, isLoading, isError } = useQuery("list", async () => {
const { data } = await axios.get("/api/list");
return data
});
return <div>...</div>
}
useMutation
import { useMutation } from "react-query";
function App(){
const [mutate] = useMutation(fn);
async function onSubmit(){
await mutate(
{},
{
onSuccess: () => {
console.log("Good Job!");
},
onError: () => {
console.log("Error!")
}
);
}
return <button onclick={onSubmit}>提交</button>
}