特性State Hook
components/Demo1.jsx
import React, {useState} from "react";
// export default class Demo1 extends React.Component{
// state = {
// count: 0
// }
// render(){
// return(
// <div>
// Hello class Hook:{this.state.count}
// </div>
// )
// }
// }
// function Demo1(){
// return(
// <div>
// Hello function Hook
// </div>
// )
// }
// export default Demo1;
const Demo1 = () => {
/**
* count: 状态
* setCount: setState -> setCount修改状态
* useState(0): 默认值
*/
const [count, setCount] = useState(10);
const [page, setPage] = useState(0);
return(
<div>
Hello function Hook:{ count } -- { page }
<button onClick={ () => { setCount(count + 1);setPage(count + 1) }}>Add</button>
</div>
)
}
export default Demo1;
特性Effect Hook
components/Demo1.jsx
// import React from "react";
// export default class Demo2 extends React.Component{
// state = {
// count: 0
// }
// componentDidMount(){
// document.title = `You clicked ${this.state.count} times`
// }
// componentDidUpdate(){
// document.title = `You clicked ${this.state.count} times`
// }
// render(){
// return(
// <div>
// Hello Demo2: {`You clicked ${this.state.count} times`}
// <button onClick={() => {this.setState({count:this.state.count += 1})}}>Add</button>
// </div>
// )
// }
// }
import React, {useState, useEffect } from "react";
const Demo2 = () => {
const [count,setCount] = useState(0);
/**
* useEffect:
* componentDidMount
* componentDidMount
* componentWillUnmount
*/
useEffect(() => {
document.title = `You clicked ${count} times`
});
return(
<div>
Hello Demo2: {`You clicked ${count} times`}
<button onClick={() => {setCount(count + 1)}}>Add</button>
</div>
)
}
export default Demo2;
State Hook和Effect Hook实例
components/Demo3/User.jsx
// import React from 'react';
// const userSet = ['张三', '李四', '王五', '赵六'];
// export default class UserGenerator extends React.Component{
// state = {
// user: userSet[0]
// }
// generateUser = () => {
// let randomIndex = Math.floor(Math.random() * userSet.length);
// let randomUser = userSet[randomIndex];
// this.setState({
// user: randomUser
// })
// }
// render () {
// return (
// <div>
// <span>{this.state.user}</span>
// <button onClick={this.generateUser}>切换</button>
// </div>
// )
// }
// }
import React, { useState } from 'react';
const userSet = ['张三', '李四', '王五', '赵六'];
const UserGenerator = () => {
const [user, setUser] = useState(userSet[0])
const generateUser = () => {
let randomIndex = Math.floor(Math.random() * userSet.length);
let randomUser = userSet[randomIndex];
setUser(randomUser)
}
return (
<div>
<span>{user}</span>
<button onClick={generateUser}>切换</button>
</div>
)
}
export default UserGenerator;
components/Demo3/Token.jsx
import React, { useState, useEffect } from "react";
class TokenForm extends React.Component{
handlerSubmit = (event) => {
event.preventDefault();
// 数据来源props
const { setToken } = this.props;
const token = this.tokeenInput.value;
if (token) {
setToken(token)
}
}
render () {
return (
<form onSubmit={this.handlerSubmit}>
<input type="text" name="token" placeholder="enter your token" ref={input => {this.tokeenInput = input}} />
</form>
)
}
}
// export default class TokenApp extends React.Component{
// state = {
// token: null
// }
// componentDidMount () {
// // 数据存在本地
// this.setState({ token: sessionStorage.getItem("token") });
// }
// setToken = token => {
// sessionStorage.setItem("token", token);
// this.setState({ token });
// }
// render () {
// const { token } = this.state;
// return (
// <div>
// <h1>Hello</h1>
// {token ? token : <TokenForm setToken={this.setToken} />}
// </div>
// )
// }
// }
const TokenApp = () => {
const [token, setToken] = useState(sessionStorage.getItem("token"));
useEffect(() => {
sessionStorage.setItem("token", token);
})
return (
<div>
<h1>Hello</h1>
{token ? token : <TokenForm setToken={setToken} />}
</div>
)
}
export default TokenApp;
特性Hook TodoList
components/Demo4/TodoForm.jsx
// import React,{useState} from 'react';
// const TodoForm = () => {
// const [value,setValue] = useState("");
// return(
// <div>
// <input type="text" value={value} onChange={(e) => setValue(e.target.value)} />
// </div>
// )
// }
// export default TodoForm;
// https://github.com/rehooks/awesome-react-hooks
import React,{useState} from "react";
const useInputValue = (initialValue) => {
const [value,setValue] = useState(initialValue);
return{
value,
onChange: e => setValue(e.target.value),
resetValue: () => setValue("")
}
}
const TodoForm = ({onSubmit}) => {
const {resetValue, ...text} = useInputValue("");
const onSubmitHandler = (e) => {
e.preventDefault();
onSubmit(text.value);
resetValue(); //清空输入框
}
return(
<form onSubmit={onSubmitHandler}>
<input type="text" {...text} />
</form>
)
}
export default TodoForm;
components/Demo4/TodoList.jsx
import React,{useState} from 'react';
import TodoForm from './TodoForm';
const TodoList = () => {
/**
* todolist是一个列表:数组
*/
const [todos,setTodos] = useState([]);
const setValue = (text) => {
// 数组的合并
/**
* a = [1,2,3]
* b = [4,5,6]
* c = 7
* [...a,...b,c]
*/
setTodos([{text},...todos]);
console.log(todos);
}
return(
<div>
<TodoForm onSubmit={setValue} />
<div>
{
todos.map((element,index) => {
console.log(element);
return (
<div key={index}>
{element.text}
</div>
)
})
}
</div>
<button onClick={() => {setTodos([])}}>clear</button>
</div>
)
}
export default TodoList;
Hook Effect性能优化
components/Demo5.jsx
// import React from "react";
// export default class Demo5 extends React.Component{
// state = {
// count: 0,
// name: "iwen"
// }
// componentDidMount(){
// document.title = `you clicked ${this.state.count} times`;
// }
// // componentDidUpdate(){
// // console.log("触发");
// // document.title = `you clicked ${this.state.count} times`;
// // }
// // 优化
// componentDidUpdate(prevProps, prevState){
// if(prevState.count !== this.state.count){
// console.log("触发");
// document.title = `you clicked ${this.state.count} times`;
// }
// }
// clickCountHandler = () => {
// this.setState({
// count: this.state.count + 1
// })
// }
// clickNameHandler = () => {
// this.setState({
// name: 'ime'
// })
// }
// render(){
// return(
// <div>
// <p>{`you clicked ${this.state.count} times`}</p>
// <p>{this.state.name}</p>
// <button onClick={this.clickCountHandler}>click count</button>
// <button onClick={this.clickNameHandler}>click name</button>
// </div>
// )
// }
// }
import React,{useState,useEffect} from "react";
const Demo5 = () => {
const [count,setCount] = useState(0);
const [name,setName] = useState('iwen');
// useEffect(() => {
// console.log("执行");
// document.title = `you clicked ${count} times`;
// })
// 优化
/**
* 第二个参数:
* []:相当于生命周期函数的:componentDidMount
* 没有第二个参数:相当于生命周期函数:componentDidMount componentDidUpdate
* [count]: 只监听count发生改变的时候,才会触发componentDidUpdate
*
* return: 相当于componentWillMount
*/
useEffect(() => {
console.log("执行");
document.title = `you clicked ${count} times`;
},[count]);
return(
<div>
<p>Your cliced {count} times</p>
<p>{name}</p>
<button onClick={() => setCount(count + 1)}>Click Count</button>
<button onClick={() => setName('ime')}>Click name</button>
</div>
)
}
export default Demo5;
特性--网络请求
components/Demo6.jsx
import React, { useState, useEffect } from "react";
const useFetch = (url) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
(async () => {
const response = await fetch(url);
const data = await response.json();
console.log(data);
setData(data);
setLoading(false);
})();
}, []);
return { data, loading }
}
const Demo6 = () => {
// const [data, setData] = useState(null);
// const [loading, setLoading] = useState(true);
// useEffect(() => {
// (async () => {
// const response = await fetch("http://iwenwiki.com/api/blueberrypai/getChengpinDetails.php");
// const data = await response.json();
// console.log(data);
// setData(data);
// setLoading(false);
// })();
// })
const { data, loading } = useFetch("http://iwenwiki.com/api/blueberrypai/getChengpinDetails.php");
return (
<div>
{loading ? <div>...loading</div> : data.chengpinDetails[0].title}
</div>
)
}
export default Demo6;
Hook useEffect实例
components/Demo7.jsx
// import React from "react"
// export default class GithubListClass extends React.Component {
// constructor(props) {
// super(props);
// this.state = {
// page: 1,
// commits: []
// };
// this.nextPage = this.nextPage.bind(this);
// this.firstPage = this.firstPage.bind(this);
// }
// nextPage () {
// this.setState({ page: this.state.page + 1 }, () => this.loadGithubCommits());
// }
// firstPage () {
// this.setState({ page: 1 }, () => this.loadGithubCommits());
// }
// loadGithubCommits () {
// const { page } = this.props;
// fetch(`https//api.github.com/search/commits?q=repo:facebook/react+css&page=${page}`, {
// method: 'GET',
// headers: new Headers({ "Accept": "application/vnd.github.cloak-preview" }),
// })
// .then(data => data.json())
// .then(response => setCommits(response.items))
// .catch(error => console.log(error))
// }
// componentDidMount () {
// this.loadGithubCommits();
// }
// render () {
// return (
// <div>
// {this.state.commits.length !== 0 && <button onClick={this.nextPage}>next page</button>}
// {this.state.commits.length !== 0 && <button onClick={this.firstPage}>first page</button>}
// {
// this.state.commits.map(c => (
// <div key={c.sha}>
// {
// c.commits && (
// <div className="commit-container">
// <p>{c.commits.committer.name}</p>
// <p>{c.commits.message}</p>
// </div>
// )
// }
// </div>
// ))
// }
// </div>
// )
// }
// }
import React, { useState, useEffect } from 'react';
const GithubListClass = () => {
const [page, setPage] = useState(1);
const [commits, setCommits] = useState([]);
const nextPage = () => {
setPage(page + 1);
}
const firstPage = () => {
setPage(1);
}
useEffect(() => {
fetch(`https//api.github.com/search/commits?q=repo:facebook/react+css&page=${page}`, {
method: 'GET',
headers: new Headers({ "Accept": "application/vnd.github.cloak-preview" }),
})
.then(data => data.json())
.then(response => setCommits(response.items))
.catch(error => console.log(error))
}, [page]); //一直执行
return (
<div>
{commits.length !== 0 && <button onClick={nextPage}>next page</button>}
{commits.length !== 0 && <button onClick={firstPage}>first page</button>}
{
commits.map(c => (
<div key={c.sha}>
{
c.commits && (
<div className="commit-container">
<p>{c.commits.committer.name}</p>
<p>{c.commits.message}</p>
</div>
)
}
</div>
))
}
</div>
)
}
export default GithubListClass;
React Hook 规则
components/Demo8.jsx
import React, { useState, useEffect } from "react";
// https://zh-hans.reactjs.org/docs/hooks-rules.html
const Demo8 = () => {
const [count, setCount] = useState(0);
useEffect(() => {
if(count === 0){
document.title = `ou clicked ${count} times`;
}
})
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
)
}
export default Demo8;
useEffect中的componentWillUnmount(副作用)
components/Demo9
import React, { Component, useState, useEffect } from 'react';
const MyAPI = {
count: 0,
subscribe (cb) {
this.intervalId = setInterval(() => {
this.count += 1;
cb(this.count)
},1000)
},
unSubscribe () {
clearInterval(this.intervalId);
this.reset();
},
reset () {
this.count = 0;
}
}
// export default class Demo9 extends Component{
// state = {
// count: 0
// }
// componentDidMount () {
// MyAPI.subscribe(count => {
// this.setState({
// count: count
// })
// })
// }
// componentWillUnmount () {
// // 清楚定时器
// MyAPI.unSubscribe();
// }
// render () {
// return (
// <div>
// {this.state.count}
// </div>
// )
// }
// }
const Demo9 = () => {
const [count, setCount] = useState(0);
/**
* 只在最顶层使用 Hook
* 不要在循环,条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层调用他们
* 只在 React 函数中调用 Hook
* 不要在普通的 JavaScript 函数中调用 Hook。
*/
useEffect(() => {
MyAPI.subscribe(currentCount => {
setCount(currentCount);
})
// 副作用的处理方式
return () => {
// 清除定时器
MyAPI.unSubscribe();
}
}, [])
return (
<div>{count}</div>
)
}
export default Demo9;
React.memo特性
components/Demo10/MemoDemo.jsx
import React from 'react';
import Child from './Child'
/**
* 注意
* React.PureComponent 中的 shouldComponentUpdate() 仅作对象的浅层比较。
如果对象中包含复杂的数据结构,则有可能因为无法检查深层的差别,产生错误的比对结果。
仅在你的 props 和 state 较为简单时,才使用 React.PureComponent,
或者在深层数据结构发生变化时调用 forceUpdate() 来确保组件被正确地更新。
你也可以考虑使用 immutable 对象加速嵌套数据的比较。
此外,React.PureComponent 中的 shouldComponentUpdate() 将跳过所有子组件树的 prop 更新。
因此,请确保所有子组件也都是“纯”的组件。
*/
export default class MemoDemo extends React.PureComponent{
state = {
time: new Date()
}
componentDidMount () {
setInterval(() => {
this.setState({
time: new Date()
})
}, 1000);
}
render(){
console.log('render');
return(
<div>
<Child seconds={1}/>
{this.state.time.toString()}
</div>
)
}
}
components/Demo10/Child.jsx
import React from 'react';
const Child = ({ seconds }) => {
console.log('Child render');
return <p>current time: {seconds}</p>
}
/**
* React.memo 为高阶组件。
如果你的组件在相同 props 的情况下渲染相同的结果,那么你可以通过将其包装在 React.memo 中调用,
以此通过记忆组件渲染结果的方式来提高组件的性能表现。
这意味着在这种情况下,React 将跳过渲染组件的操作并直接复用最近一次渲染的结果。
*/
export default React.memo(Child);
App.js
import logo from './logo.svg';
import Demo1 from "./components/Demo1"
import Demo2 from "./components/Demo2"
import User from "./components/Demo3/User"
import Token from "./components/Demo3/Token"
import Demo5 from "./components/Demo5"
import Demo6 from "./components/Demo6"
import Demo7 from "./components/Demo7"
import Demo8 from "./components/Demo8"
import Demo9 from "./components/Demo9"
import Demo10 from "./components/Demo10/MemoDemo"
import TodoList from "./components/Demo4/TodoList"
function App () {
return (
<div className="App">
<Demo1 />
<Demo2 />
<User />
<Token />
<TodoList />
<Demo5 />
<Demo6 />
<Demo7 />
<Demo8 />
<Demo9 />
<Demo10 />
</div>
);
}
export default App;
持续更新......