[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;