useState
不会改变原有值,每回返回一个新的数组,第一个参数读,第二个参数写(是一个函数)
import React, { useState } from 'react';
function Example() {
// 声明一个新的叫做 “count” 的 state 变量
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
useEffect
接受一个函数和一个数组,数组如果不写就是每回调用,[]
等于第一次调用[]
里是哪个参数就在哪个参数变化时调用
在函数里面return
一个新数组等于消亡时调用
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {
// Update the document title using the browser API
document.title = `You clicked ${count} times`;
});
useEffect(() => {
// Update the document title using the browser API
document.title = `You clicked ${count} times`;
},[count]);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
useRef
useRef是一个对象里面只有一个current值
对一个div的引用
const container = useRef(null)
container.current.style.color = 'white'
return(
<div ref={container} >hi</div>
)
forwardRef
组件里传递props
是无法传递ref
的,可以用forwardRef
把组件包裹起来,箭头函数的参数传入ref
即可
function App() {
const buttonRef = useRef(null);
return (
<div className="App">
<Button2 ref={buttonRef}>按钮</Button2>
{/* 看浏览器控制台的报错 */}
</div>
);
}
//const Button2 = props => {
// return <button className="red" {...props} />;
//};
const Button2 = (props, ref) =>{
return <button ClassName="red" ref={ref} {...props}/>
}
const x = React.forwardRef(Button2)
useContext
相当于一个局部的全局变量链接
//const MyContext = React.createContext(defaultValue);
const x = React.createContext(null)
const [theme,setTheme] = useState("red")
function App(){
<x.provider value={{theme,setTheme}}>
<Child>
...
</x.provider>
}
function Child(){
const {setTheme} = useContext(x)
<button onClick(()=>{setTheme("blue")})>color</button>
}
<MyContext.Provider value={/* 某个值 */}>
每个 Context 对象都会返回一个 Provider React 组件,它允许消费组件订阅 context 的变化。Provider
接收一个 value
属性,传递给消费组件。一个 Provider 可以和多个消费组件有对应关系。多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据。
当 Provider
的 value
值发生变化时,它内部的所有消费组件都会重新渲染。从 Provider 到其内部 consumer 组件(包括 .contextType 和 useContext)的传播不受制于 shouldComponentUpdate 函数,因此当 consumer 组件在其祖先组件跳过更新的情况下也能更新。
useReducer
先创建初始值init
创建所有操作reducer(state,action)
传给useReducer,得到读和写接口
调用 写 ({type:操作类型})
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>
);
}
用来代替Redux
将所有数据集中在一个store里面
将所有操作集中在reducer里
创建一个Context
创建对函数读写的API
将第四步的内容放到第三步的Context
用Context.Provider将Context提供给所有组件
各个组件使用Context获取读写API
const store = {
user: null,
books: null,
movies: null
};
function 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();
}
}
const Context = React.createContext(null);
function App() {
const [state, dispatch] = useReducer(reducer, store);
const api = { state, dispatch };
return (
<Context.Provider value={api}>
<User />
<hr />
<Books />
<Movies />
</Context.Provider>
);
}
function User() {
const { state, dispatch } = useContext(Context);
useEffect(() => {
ajax("/user").then(user => {
dispatch({ type: "setUser", user: user });
});
}, []);
return (
<div>
<h1>个人信息</h1>
<div>name: {state.user ? state.user.name : ""}</div>
</div>
);
}
function Books() {
const { state, dispatch } = useContext(Context);
useEffect(() => {
ajax("/books").then(books => {
dispatch({ type: "setBooks", books: books });
});
}, []);
return (
<div>
<h1>我的书籍</h1>
<ol>
{state.books ? state.books.map(book => <li key={book.id}>{book.name}</li>) : "加载中"}
</ol>
</div>
);
}
function Movies() {
const { state, dispatch } = useContext(Context);
useEffect(() => {
ajax("/movies").then(movies => {
dispatch({ type: "setMovies", movies: movies });
});
}, []);
return (
<div>
<h1>我的电影</h1>
<ol>
{state.movies
? state.movies.map(movie => <li key={movie.id}>{movie.name}</li>)
: "加载中"}
</ol>
</div>
);
}
useMemo
减少多余的render
App里面的Child组件不需要再次执行可以用React.memo
包起来
如果子组件了里面添加的监听事件触发则不行,需要改为useMemo
即可
function App() {
const [n, setN] = React.useState(0);
const [m, setM] = React.useState(0);
const onClick = () => {
setN(n + 1);
};
return (
<div className="App">
<div>
<button onClick={onClick}>update n {n}</button>
</div>
<Child data={m}/>
{/* <Child2 data={m}/> */}
</div>
);
}
function Child(props) {
console.log("child 执行了");
...
console.log('执行代码')
return <div>child: {props.data}</div>;
}
const Child2 = React.memo(Child);
useMemo
return返回一个函数,语法糖可以改写为useCallback
const ChildEvent = useMemo(()=>{
return ()=>{
console.log('xxx')
}
})
const ChildEvent = useCallback(()=>{
console.log('xxx')
})