React 16.8 Hooks 尝鲜体验

导读


  • Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性,编写具有 Hook 的函数组件对比以前的 class 组件来说,其好处有以下几点:
    1 . 不再有生命周期函数
    2 . 不再有 this 指向
    3 . 函数式编程
    4 . 不用引入额外的状态管理

例子:

  • useState(存储状态和改变状态的函数)
import  React, { useState } from "react";

const App = () => {
  const [count, setCount] = useState(0);    // useState中的为count初始值 
  return (
    <div className="App">
      <p>You clicked {count} times!</p>
      <button onClick={() => setCount(count + 1)}>提交</button>
    </div>
  );
};

export default App;
  • useEffect(可以理解为具有以前 class 的 ComponentDidMount,ComponentDidUpdate,ComponentWillUnMount 钩子功能的副作用函数)
import React, { useState, useEffect } from "react";
import { BrowserRouter, Route, Link } from "react-router-dom";

const Home = () => {
  useEffect(() => {
    console.log(`useEffect => 来了老弟 - Home`);   // 只要组件加载或更新都会执行
    return () => {
      console.log(`Home - 走了`);
    };  // 用来清除本次副作用,当组件执行下一次副作用函数时会执行
  }, []);    
// useEffect第二个参数传空值代表当该组件卸载(ComponentWillUnMount)时才执行清除副作用函数(return的函数)
// useEffect第二个参数不为空值,则对应当依赖值改变时才执行副作用函数,清除副作用函数执行机制同上
  return <h2>Vern.com</h2>;
};

const List = () => {
  useEffect(() => {
    console.log(`useEffect => 来了老弟 - PageList`);
    return () => {
      console.log(`PageList - 走了`);
    };
  }, []);
  return <h2>ListPage</h2>;
};

const Counter = () => {
  let count = useContext(CountContext);
  return <h2>{count}</h2>;
};

const App = () => {
  const [count, setCount] = useState(0);
  useEffect(() => {
    console.log(`useEffect => you clicked ${count} times!`);  // 每次渲染/更新都会执行
  });
  return (
    <div className="App">
      <p>You clicked {count} times!</p>
      <button onClick={() => setCount(count + 1)}>提交</button>
      <BrowserRouter>
        <ul>
          <li>
            <Link to="/">首页</Link>
          </li>
          <li>
            <Link to="/list">列表</Link>
          </li>
        </ul>
        <Route path="/" exact component={Home} />
        <Route path="/list" exact component={List} />
      </BrowserRouter>
    </div>
  );
};

export default App;

当 useEffect 第二个参数设为空值时:


useEffect1

useEffect2

当不设置 useEffect 第二个参数时(默认只要组件有变化就会执行解绑函数):


image.png
  • useContext(用于父子组件传值)
import React, { useState, createContext, useContext } from "react";

const CountContext = createContext();

const Counter = () => {
  let count = useContext(CountContext);
  return <h2>{count}</h2>;
};

const App = () => {
  const [count, setCount] = useState(0);

  return (
    <div className="App">
      <p>You clicked {count} times!</p>
      <button onClick={() => setCount(count + 1)}>提交</button>
      <CountContext.Provider value={count}>
        <Counter />
      </CountContext.Provider>
    </div>
  );
};

export default App;
  • useReducer(类似 Redux 的 reducer)
import React, { useReducer } from "react";

const init = initialCount => {
  return { count: initialCount };
};

const countReducer = (state, action) => {
  switch (action.type) {
    case "add":
      return { count: state.count + 1 };
    case "sub":
      return { count: state.count - 1 };
    case "reset":
      return init(action.payload);
    default:
      throw new Error();
  }
};

const App = () => {
  const [state, dispatch] = useReducer(countReducer, 0, init);
  // useReducer 第二个参数为状态的初始值,第三个参数是自定义函数

  return (
    <>
      <h2>现在的分数是{state.count}分</h2>
      <button onClick={() => dispatch({ type: "reset", payload: 0 })}>
        Reset
      </button>
      <button onClick={() => dispatch({ type: "add" })}>+</button>
      <button onClick={() => dispatch({ type: "sub" })}>-</button>
    </>
  );
};

export default App;
  • useContext 和 useReducer 做类似 Redux 的功能
    默认红色

    点击变蓝

    点击变黄
// 入口文件
import React from "react";
import Body from "./views/home/body";
import Header from "./views/home/header";
import { Color } from './views/home/hooks';   
// 类似 Hoc 导出通过 ColorContext 包裹后的组件,也就是使用传递过来的状态

const App = () => {
  return (
    <>
      <Color>
        <Header />
        <Body />   
      </Color>
    </>
  );
};

export default App;
import React, { useContext } from "react";
import { ColorContext } from "./hooks";

const Header = () => {
  const {home} = useContext(ColorContext);
  return <p style={{color: home.color}}>我是一段变色文字</p>;
};

export default Header;
import React, { useContext } from "react";
import { ColorContext, CHNAGE_COLOR } from "./hooks";

const Body = () => {
  const { dispatch } = useContext(ColorContext);
  return (
    <>
      <button onClick={() => dispatch({type: CHNAGE_COLOR, color: 'blue'})}>蓝色</button>
      <button onClick={() => dispatch({type: CHNAGE_COLOR, color: 'yellow'})}>黄色</button>
    </>
  );
};

export default Body;
import React, { createContext, useReducer } from "react";

export const ColorContext = createContext({});

export const CHNAGE_COLOR = "change_color";

const reducer = (state, action) => {
  switch (action.type) {
    case CHNAGE_COLOR:
      return {
        ...state,
        color: action.color
      };
    default:
      return state;
  }
};

export const Color = props => {
  const [home, dispatch] = useReducer(reducer, { color: "red" });
  return (
    <ColorContext.Provider value={{ home, dispatch }}>
      {props.children}
    </ColorContext.Provider>
  );
};

总结

  • 个人的话目前使用还是不太熟悉,但是能理清逻辑调用,至于实践上真正优秀的地方暂时还没什么感觉,全局 useReducer 同理使用,对应一个全局 createContext,大家可以去 React 官网查阅相关用法,这里只供个人加深印象而作 ^ _ ^.
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容