About React 2

172 阅读2分钟

7.Hooks API

  • React 16.7 以后开始

  • npm info react versions

  • 函数组件中也可以有自己的状态,不非得Class组件了

  • Hooks can only be called inside the body of a function component

  • React Class 组件写法

import React from "react";
export default class App extends React.Component {
  constructor() {
    super();
    this.state = {
      count: 0
    };
  }
  add = () => {
    this.setState({
      count: this.state.count + 1
    });
  };
  minus = () => {
    this.setState({
      count: this.state.count - 1
    });
  };
  render() {
    return (
      <div>
        <div>{this.state.count}</div>
        <div>
          <button onClick={this.add}>+1</button>
          <button onClick={this.minus}>-1</button>
        </div>
      </div>
    );
  }
}

7.1 useState

import { useState } from "react";
let [值,更新函数] = useState(初始值);
import React from "react";
import "./styles.css";
import { useState } from "react";

export default function App() {
  // let count = 0;
  // let add = function () {};
  const [count, setCount] = useState(100);
  const [user, setUser] = useState({
    name: "paul",
    age: 18,
    hobbies: ["抽烟", "喝酒", "烫头"]
  });
  const add = () => {
    setCount(count + 1);
  };
  const minus = () => {
    setCount(count - 1);
  };
  const old = () => {
    setUser({
      ...user,
      age: user.age + 1
    });
  };
  const addHobby = () => {
    let newHobby = "打麻将";
    setUser({
      ...user,
      hobbies: [...user.hobbies, newHobby]
    });
  };
  return (
    <div>
      <div>{count}</div>
      <div>
        <button onClick={add}>+1</button>
        <button onClick={minus}>-1</button>
      </div>
      <div>{user.age}</div>
      <div>{user.hobbies.join("-")}</div>
      <div>
        <button onClick={old}>+1</button>
        <button onClick={addHobby}>增加爱好</button>
      </div>
    </div>
  );
}

7.2 useEffect

  • 副作用(Side Effect): 函数或者表达式的行为依赖于外部世界
function fn1() {console.log(1, 2)}  // console.log就是副作用,外部的
function fn2(a, b) {return a + b}
// 如果修改了 console.log = function() {},再执行fn1(),结果不受控制
fn1是一个有副作用的函数,fn2是一个纯函数
  • Effect Hook为函数式组件增添了执行 side Effect的能力
  • Effect Hook 可以让你在函数组件中执行副作用操作
    • 把副作用都写在useEffect中
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 就是外部来的浏览器API
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

8. React-Router

8.1 使用hash做路由

import React, { useState } from "react";
import "./styles.css";
function Box1() {
  return <div class="box">注册</div>;
}
function Box2() {
  return <div class="box">登录</div>;
}
export default function App() {
  let hash = window.location.hash;
  let initUi = hash === "#signup" ? "注册" : "登录";
  let [ui, setUi] = useState(initUi);
  const onClickLogin = () => {
    setUi("登录");
    window.location.hash = "login";
  };
  const onClickSignUp = () => {
    setUi("注册");
    window.location.hash = "signup";
  };
  return (
    <div className="App">
      <button onClick={onClickLogin}>登录</button>
      <button onClick={onClickSignUp}>注册</button>
      <div>{ui === "注册" ? <Box1 /> : <Box2 />}</div>
    </div>
  );
}
  • 直接改path,浏览器会认定为跳转页面,会刷新
    • 会404
window.location.pathname = '/login'
window.location.pathname = '/signup'
  • Html5提供的pushState API,不会刷新页面
    • 但是后端如果将所有请求路径指向首页,可以这么做
    • 否则会404
window.history.pushState(null, '', '/login')
let path = window.location.pathname

hash 和 history.pushState 在处理多路由情况下非常局限

8.2 React-Router

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import "./styles.css";

function Box1() {
  return <div class="box">注册</div>;
}
function Box2() {
  return <div class="box">登录</div>;
}
function Welcome() {
  return <div class="box">欢迎</div>;
}
function App() {
  return <div className="App">App</div>;
}
const rootElement = document.getElementById("root");
ReactDOM.render(
  <Router>
    <div>
      <div>
        <Link to="/">
          <button>首页</button>
        </Link>
        |<Link to="/login">登录</Link> |<Link to="/signup">注册</Link> |
        <Link to="/welcome">欢迎</Link>
      </div>
      <Route path="/" exact component={App} />
      <Route path="/login" component={Box2} />
      <Route path="/signup" component={Box1} />
      <Route path="/welcome" component={Welcome} />
    </div>
  </Router>,
  rootElement
);

8. 生命周期

8.1 Vanilla.js

// 研究红色框框的生老病死
let app = document.getElementById("app");

// create div 在内存中
let div = document.createElement("div");
div.style.border = "1px solid red";

let state = 1;

// componentWillMount()

// render && update
div.innerHTML = `
  <p>${state}</p>
  <button>+1</button>
  <button>die</button>
`;

// mount div 挂载
app.appendChild(div);

div.querySelector("button").onclick = () => {
  state += 1;
  // update div
  div.querySelector("p").innerText = state;
};

// destory all
div.querySelectorAll("button")[1].onclick = () => {
  div.querySelector("button").onclick = null;
  div.querySelectorAll("button")[1].onclick = null;
  div.remove();
  div = null; // destroy div
};

8.2 React中

import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";

let div = document.createElement("div");
document.body.appendChild(div);
console.log = function(content) {
  div.innerHTML += `${content}<br>`;
};

class Baba extends React.Component {
  constructor() {
    super();
    this.state = {
      hasChild: true
    };
  }
  onClick() {
    this.setState({
      hasChild: false
    });
  }
  callSon() {
    this.setState({
      word: "你还好吧"
    });
  }
  render() {
    return (
      <div>
        我是你爸爸
        <button onClick={() => this.onClick()}>kill son</button>
        <button onClick={() => this.callSon()}>call son</button>
        {this.state.hasChild ? <App word={this.state.word} /> : null}
      </div>
    );
  }
}

class App extends React.Component {
  onClick() {
    console.log("用户点击了");
    this.setState({
      n: this.state.n + 1
    });
  }
  updateX() {
    this.setState({
      x: this.state.x + "!"
    });
  }
  constructor() {
    super();
    this.state = {
      n: 0,
      x: "不展示"
    };
  }
  componentWillMount() {
    console.log("将要 mount App");
  }
  render() {
    // update
    console.log("填充/更新 App 的内容");
    return (
      <div className="App">
        {this.state.n}
        <br />
        我爸说 {this.props.word}
        <br />
        <button onClick={() => this.onClick()}>+1</button>
        <button onClick={() => this.updateX()}>update x</button>
      </div>
    );
  }
  componentDidMount() {
    console.log("mount App 完毕");
  }
  componentWillUpdate() {
    console.log("update App 之前");
  }
  shouldComponentUpdate(nextProps, nextState) {
    console.log("要不要更新呢?");
    if (this.state.n === nextState.n) {
      return false;
    } else {
      return true;
    }
  }
  //update is render
  componentDidUpdate() {
    console.log("update App 之后");
  }
  componentWillUnmount() {
    console.log("App 快要死了,记得喂狗");
  }
  componentWillReceiveProps() {
    console.log("我爸说话了");
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<Baba />, rootElement);

9. React中的CSS方案

9.1 传统CSS方案

9.2 styled-components

9.3 emotion