Hoot新特性

特性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;

持续更新......

posted on 2021-03-14 22:50  铃之森  阅读(109)  评论(0编辑  收藏  举报

导航