useState
- 使用状态
- const [n,setN] = React.useState(0)
- const [user,setUser] = React.useState({name:'F'})
- 注意事项
- 如果state是一个对象,不能部分setState,因为setState不会帮我们合并属性
- setState(obj)如果obj地址不变,那么React就认为数据没有变化
- setState接受函数,setN(i => i + 1)
import React, { useState } from "react";
import ReactDOM from "react-dom";
function App() {
const [n, setN] = useState(0);
const onClick = () => {
// setN(n + 1);
// setN(n + 1); // 你会发现 n 不能加 2
setN(i=>i+1)
setN(i=>i+1)
};
return (
<div className="App">
<h1>n: {n}</h1>
<button onClick={onClick}>+2</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
export default App;
useReducer
const initial = {n:0}
const reducer = (state, action) => {
if(action.type === 'add') {
return {n: state.n + action.number}
} else if(action.type === 'multi') {
return {n: state.n * 2}
} else {
throw new Error('unknown type')
}
}
function App() {
const [state, dispatch] = useReducer(reducer, initial)
const {n} = state
const onClick = ()=>{
dispatch({type: 'add', number:1})
}
const onClick2 = ()=>{
dispatch({type: 'add', number: 2})
}
return (
<div className="App">
<h1>n: {n}</h1>
<button onClick={onClick}>+1</button>
<button onClick={onClick2}>+2</button>
</div>
)
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
export default App;
用useReducer的表单例子:
const initFormData = {
name: "",
age: 18,
nationality: "汉族",
};
function reducer(state, action) {
switch (action.type) {
case "patch":
return { ...state, ...action.formData };
case "reset":
return initFormData;
default:
throw new Error();
}
}
function App3() {
const [formData, dispatch] = useReducer(reducer, initFormData);
// const patch = (key, value)=>{
// dispatch({ type: "patch", formData: { [key]: value } })
// }
const onSubmit = () => {};
const onReset = () => {
dispatch({ type: "reset" });
};
return (
<form onSubmit={onSubmit} onReset={onReset}>
<div>
<label>
姓名
<input
value={formData.name}
onChange={(e) =>
dispatch({ type: "patch", formData: { name: e.target.value } })
}
/>
</label>
</div>
<div>
<label>
年龄
<input
value={formData.age}
onChange={(e) =>
dispatch({ type: "patch", formData: { age: e.target.value } })
}
/>
</label>
</div>
<div>
<label>
民族
<input
value={formData.nationality}
onChange={(e) =>
dispatch({
type: "patch",
formData: { nationality: e.target.value },
})
}
/>
</label>
</div>
<div>
<button type="submit">提交</button>
<button type="reset">重置</button>
</div>
<hr />
{JSON.stringify(formData)}
</form>
);
}
useReducer代替redux
//App.js
import Context from "./Context";
import User from "./components/user";
import Books from "./components/books";
import Movies from "./components/movies";
import userReducer from "./reducers/user_reducer";
import booksReducer from "./reducers/books_reducer";
import moviesReducer from "./reducers/movies_reducer";
const store = {
user: null,
boosk: null,
movies: null,
};
const obj = {
...userReducer,
...booksReducer,
...moviesReducer,
};
function reducer(state, action) {
const fn = obj[action.type];
if (fn) {
return fn(state, action);
} else {
throw new Error("报错了");
}
}
/*
const reducer = (state, action) => {
switch (action.type) {
case "setUser":
return { ...state, user: action.user };
case "setBooks":
return { ...state, books: action.books };
case "setMovies":
return { ...state, movies: action.movies };
default:
throw new Error();
}
};
*/
function App() {
const [state, dispatch] = useReducer(reducer, store);
return (
<Context.Provider value={{ state: state, dispatch: dispatch }}>
<User />
<hr />
<Books />
<Movies />
</Context.Provider>
);
}
const div = document.getElementById("root");
ReactDOM.render(<App />, div);
//user_reducer.js
export default {
setUser: (state, action) => {
return { ...state, user: action.user };
},
};
//user.js
function User() {
const { state, dispatch } = useContext(Context);
useEffect(() => {
ajax("/user").then((user) => {
console.log('user',user)
dispatch({ type: "setUser", user: user });
});
}, []);
return (
<div>
<h1>个人信息</h1>
<div>name: {state.user ? state.user.name : ""}</div>
</div>
);
}
export default User;
useContext
import React from "react";
const Context = React.createContext(null);
export default Context;
function App() {
const [state, dispatch] = useReducer(reducer, store);
return (
<Context.Provider value={{ state: state, dispatch: dispatch }}>
<User />
<hr />
<Books />
<Movies />
</Context.Provider>
);
}
useEffect
用途
- 作为componentDidMount使用,[ ]作第二个参数
- 作为componentDidUpdate使用,可指定依赖
- 作为componentWillUnmount使用,通过return
- 以上三种用途可同时存在
特点 如果同时存在多个useEffect,会按照出现次序执行
function UseEffectDemo() {
const [n, setN] = useState(0);
const onClick = ()=>{
setN(i => i + 1)
}
const afterRender = useEffect;
afterRender(() => {
console.log("第一次渲染之后执行这一句话");
},[])
afterRender(()=>{
console.log("任何一个state变化时都执行");
})
afterRender(()=>{
console.log("n变化了");
},[n])
return (
<div>
n:{n}
<button onClick={onClick}>+1</button>
</div>
)
}
useMemo
import React, { useMemo } from "react";
function UseMemoDemo() {
const [n, setN] = React.useState(0);
const [m, setM] = React.useState(0);
const onClick = () => {
setN(n + 1);
};
const onClick2 = () => {
setM(m + 1);
};
const onClickChild = useMemo(() => {
const fn = (div) => {
console.log("on click child, m: " + m);
console.log(div);
};
return fn;
}, [m]);
return (
<div className="App">
<div>
<button onClick={onClick}>update n {n}</button>
<button onClick={onClick2}>update m {m}</button>
</div>
<Child2 data={m} onClick={onClickChild} />
</div>
);
}
function Child(props) {
console.log("child 执行了");
return (
<div onClick={(e) => props.onClick(e.target)}>child: {props.data}</div>
);
}
const Child2 = React.memo(Child);
export default UseMemoDemo;
useRef
import React, { useEffect, useMemo, useRef } from "react";
function UseRefDemo() {
console.log("App 执行");
const count = useRef(0);
const [n, setN] = React.useState(0);
const onClick = ()=>{
setN(n+9);
}
useEffect(()=>{
count.current += 1;
console.log(count.current);
})
return (
<div className="App">
<div>
<button onClick={onClick}>update n {n}</button>
</div>
</div>
)
}
export default UseRefDemo;
forwardRef
import React, { useEffect, useMemo, useRef } from "react";
function ForwardRefDemo() {
const buttonRef = useRef(null);
return (
<div className="App">
<Button3 ref={buttonRef}>按钮</Button3>
</div>
)
}
const Button3 = React.forwardRef((props, ref) => {
console.log('ref',ref);
return <button className="red" ref={ref} {...props}/>
})
export default ForwardRefDemo;
自定义Hook
//useList.js
import { useState, useEffect } from "react";
const useList = () => {
const [list, setList] = useState(null);
useEffect(() => {
ajax("./list").then((list) => {
console.log("list", list);
setList(list);
});
}, []); //确保只在第一次运行
return {
list: list,
setList: setList,
addItem: (name) => {
setList([...list, { id: Math.random(), name: name }]);
},
deleteIndex: (index) => {
setList(list.slice(0, index).concat(list.slice(index + 1)));
},
};
};
export default useList;
function ajax() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve([
{ id: 1, name: "Mike" },
{ id: 2, name: "Jack" },
{ id: 3, name: "Alice" },
{ id: 4, name: "Bob" },
]);
}, 2000);
});
}
import React, { useEffect, useReducer, useState } from "react";
import ReactDOM from "react-dom";
import useList from "./hooks/useList";
function UseListHooksDemo() {
const { list, deleteIndex, addItem } = useList();
return (
<div className="App">
<h1>List</h1>
{list ? (
<ol>
{list.map((item, index) => (
<li key={item.id}>
{item.name}
<button
onClick={() => {
deleteIndex(index);
}}
>
x
</button>
</li>
))}
</ol>
) : (
"加载中..."
)}
</div>
);
}
export default UseListHooksDemo;