[React] Hook
useEffect
import React, { useEffect, useState } from 'react';
const [FLG1, setFLG1] = useState(true)
const [FLG2, setFLG2] = useState(true)
////////////////////////////////////////
// useEffect 啥时用?
// -> 有一些处理不想让它每次组件渲染时都执行
// -> 异步调用时执行
////////////////////////////////////////
/*
useEffect(() => {
console.log("Home.useEffect")
});
// }, []);
// }, [FLG1]);
*/
Ajax 从后端取数据。与服务器端保持长链接,比如股票行情图。

通过一个按钮函数,从而触发useEffect,对“长链接”进行结束操作~
import React, { useEffect, useState } from 'react'; const Home = () => { const [time, updateTime] = useState(Date.now()); const [searchCondition, setSearchCondition] = useState("游戏") const [newsContent, setNewsContent] = useState("") useEffect(() => { setNewsContent(`${searchCondition}新闻:${Math.random().toString()}\n${newsContent}`); // 不断地追加显示的内容~ const timeoutId = setTimeout(() => updateTime(Date.now()), 3000); return () => { clearTimeout(timeoutId); } }, [time]); useEffect(() => { ///////////////////////////////////////////// // cleanup 就看这里,其他的不要看 return () => { console.log(searchCondition, "cleanup") } ///////////////////////////////////////////// }, [searchCondition]);
const btn_search_click = () => { const category = ["游戏", "军事", "股票", "美食", "体育"]; const newCategory = category[Math.floor(Math.random() * category.length)]; setNewsContent("") setSearchCondition(newCategory); }
return ( <React.Fragment> <h1>Home</h1> <h2 className="text-success">显示条件: {searchCondition.toString()}</h2> <div className="p-1"> <button onClick={btn_search_click} className="btn btn-primary btn-lg mx-1">检索</button> </div> <hr /> <pre className="text-secondary"> {newsContent} </pre> </React.Fragment> ) } export default Home;
useContext
createContext是个特殊的标签,可以将value中的内容提供给该标签下子组件们 instead of props。
# App.js
import React, { createContext, useState } from 'react' import { Route, Switch, Redirect } from 'react-router-dom'; import Header from './components/Header'; import Home from './pages/Home'; import About from './pages/About'; // 创建上下文对象 export const DeeplearnAWSContext = createContext() function App() {
// 创建上下文数据对象 const [deeplearnAWS, setDeeplearnAWS] = useState({ sitename: '深学AWS', author: 'Koma', sayHelo: (pname) => { console.log(`Helo ${pname}. ${Math.random().toString()}`) } }) return ( <div> <Header></Header> <div className="p-4"> {/* 提供上下文数据 */} <DeeplearnAWSContext.Provider value={deeplearnAWS}> <Switch> <Route path="/" exact> <Redirect to="/home"></Redirect> </Route> <Route path="/home"> <Home></Home> </Route> <Route path="/about"> <About></About> </Route> </Switch> </DeeplearnAWSContext.Provider> </div> </div> ); } export default App;
在子组件中,获得参数。
import React, { useContext } from 'react' // 引入上下文对象 import { DeeplearnAWSContext } from '../App'; const About = () => { // 实例化上下文对象 const DeeplearnAWS = useContext(DeeplearnAWSContext) console.log(DeeplearnAWS) return ( <React.Fragment> <h1>About</h1> <hr /> {/* 使用上下文数据 */} <h2>sitename: {DeeplearnAWS.sitename}</h2> <h3>author: {DeeplearnAWS.author}</h3> <button className="btn btn-success" onClick={() => DeeplearnAWS.sayHelo("React")}>SayHelo</button> </React.Fragment> ) } export default About;
useReducer
复杂状态管理。比 useState 更好~
onClick 方法调用 dispatch改变useReducer对应的 状态count。
import React, { useReducer } from 'react' const Clicker = () => {
const [count, dispatch] = useReducer( (count, action) => { // 本函数应该返回新的 count 值 console.log(count, action) switch (action) { case "add": return count + 1 case "minus": return count - 1 default: return 100 } }, 100) return ( <React.Fragment> <h1>Clicker</h1> <hr /> <h2 className={count < 100 ? "text-danger" : "text-dark"}>{count}</h2> <div className="py-2 bg-light"> <button className="btn btn-primary mx-1" onClick={() => { dispatch("add") }}>加击一次</button> // dispatch 的参数比较简洁 <button className="btn btn-success mx-1" onClick={() => { dispatch("minus") }}>减击一次</button> </div> <hr /> <div className="py-2 bg-light"> <button className="btn btn-info mx-1" onClick={() => { dispatch("下回分解") }}>加击10次</button> <button className="btn btn-warning mx-1" onClick={() => { dispatch("下回分解") }}>减击10次</button> </div> </React.Fragment> ) } export default Clicker;
控制加减的次数,那就增强 dispatch 的参数:action to { type: "add", step: 10 }
也可以是一个dict,具体看如下代码示范。
import React, { useReducer } from 'react' const Clicker = () => { const [count, dispatch] = useReducer((count, action) => { // 本函数应该返回新的 count 值 console.log(count, action) switch (action.type) { case "add": return count + action.step case "minus": return count - action.step default: return 100 } }, 100) return ( <React.Fragment> <h1>Clicker</h1> <hr /> <h2 className={count < 100 ? "text-danger" : "text-dark"}>{count}</h2> <div className="py-2 bg-light"> <button className="btn btn-primary mx-1" onClick={() => { dispatch({ type: "add", step: 1 }) }}>加击一次</button> <button className="btn btn-success mx-1" onClick={() => { dispatch({ type: "minus", step: 1 }) }}>减击一次</button> </div> <hr /> <div className="py-2 bg-light"> <button className="btn btn-info mx-1" onClick={() => { dispatch({ type: "add", step: 10 }) }}>加击10次</button> <button className="btn btn-warning mx-1" onClick={() => { dispatch({ type: "minus", step: 10 }) }}>减击10次</button> </div> </React.Fragment> ) } export default Clicker;
useMemo
感觉,这个比较常用,属于一种常规优化。

通过”状态 FLG2" 过度一下,再经过 useMemo控制“渲染的变量“。
import React, { useState, useMemo } from 'react'
import Header from './components/Header';
function App() {
console.log("----- App.js run -----")
const [FLG, setFLG] = useState(false)
const [FLG2, setFLG2] = useState(false)
// 每次渲染执行,通过大量计算,得出AI结果
const AIResult = () => {
console.log("AI Running...")
var result = 0
for (var i = 1; i <= 100; i++)
result += i;
return result
}
// 只有当 FLG2 改变时才执行
const AIResult2 = useMemo(() => {
console.log("AI2 Running...")
var result = 0
for (var i = 1; i <= 100; i++)
result += i;
return result
}, [FLG2])
return (
<div>
<Header></Header>
<div className="p-4">
<div className="fs-1">{FLG.toString()}, {FLG2.toString()}</div>
<div>
<button className="btn btn-success" onClick={() => setFLG(!FLG)}>更新标记</button>
<button className="btn btn-info mx-1" onClick={() => setFLG2(!FLG2)}>更新标记2</button>
</div>
<hr />
<h3>AI :{AIResult().toString()}</h3>
<h3>AI2:{AIResult2.toString()}</h3>
</div>
</div>
);
}
export default App;
useFetch
需要单独安装下这个包。
$ npm install use-http --save
$ npm start
如下,点击某个按钮,读服务端数据,获得相应的列表并显示。

import React, { useState, useEffect } from 'react'
import useFetch from 'use-http' // 单独安装的包以支持
import Header from './components/Header';
function App() {
console.log("----- App.js run -----")
const { get, post, response, loading, error } = useFetch('https://swapi.dev/api')
const [dataset, setDataset] = useState([])
// 启动装载
useEffect(() => { search('films') }, [])
async function search(presource) {
console.log("search", presource)
const datalist = await get('/' + presource)
if (response.ok) setDataset(datalist.results)
else setDataset([])
}
const btn_click = async (pvalue) => {
await search(pvalue)
}
return (
<div>
<Header></Header>
<div className="p-4">
<h1 className="border-bottom">useFetch</h1>
<div>
<button className="btn btn-success mx-1" onClick={() => btn_click("films")}>电影</button>
<button className="btn btn-primary mx-1" onClick={() => btn_click("starships")}>飞船</button>
<button className="btn btn-info mx-1" onClick={() => btn_click("people")}>人物</button>
<button className="btn btn-warning mx-1" onClick={() => btn_click("aws")}>AWS</button>
</div>
<hr />
<div>
{dataset.map((item, index) => (
< div key={index} > {index + 1}. {item.title || item.name}</div>
))}
</div>
</div>
</div >
);
}
export default App;
useInput
处理表单输入,可顺便参考下:[React] Review
需要安装 React Hooks:
$ npm install rooks --save
React Hooks 是 对React function 组件的一种扩展,通过一些特殊的函数,让无状态组件拥有状态组件才拥有的能力。 Hooks 是React 函数组件中的一类特殊函数,通常以use 开头。
(类似vue的双向绑定)

如果一个表格中需要多个输入,则定义多个 useInput 即可。
import React, { useState } from 'react';
import { useInput } from "rooks";
import Header from './components/Header';
function App() {
const inputUserName = useInput("koma"); // 可见默认值是个"koma"
console.log(inputUserName)
return (
<div>
<Header></Header>
<div className="py-2 px-4">
<h1>React Rooks</h1>
<form class="row g-3">
<div class="col-6">
<input className="form-control" {...inputUserName} /> // 这里写入后,自动触发并渲染~
</div>
<div class="col-auto">
<button type="button" class="btn btn-primary" onClick={() => { alert(inputUserName.value) }}>确认</button>
</div>
</form>
<p>
输入内容: <b>{inputUserName.value}</b>
</p>
</div>
</div>
);
}
export default App;

浙公网安备 33010602011771号