react 学习笔记

react 学习笔记

注意事项

  • React 组件名称必须以大写字母开头
  • React Hook 名称必须以“use”开头

关键技术点总结

  • Redux(如类可丝) 状态框架
  • hook 函数式组件
  • class 类组件

技能点hooks-intro

5大核心概念

1.组件
2.JSX
3.props & state
4.组件API
5.组件类型

目录

创建项目

# js
create-react-app my-app
# ts
create-react-app react-demo-01-ts --template typescript

组件声明周期

  • componentDidMount() 方法会在组件已经被渲染到 DOM 中后运行
  • componentDidUpdate()在更新后会被立即调用
  • componentWillUnmount() 组件从DOM中移除调用

组件写法

概念:你编写所有的React 代码基本上就是包含许多小组件在内的大组件。

class 写法

class MyComponent extends React.Component {
  render() {
    return <p>Hello World!<p>;
  }
}

function函数式写法(无状态组件)

当然在这样的组件当中你也没有办法使用 setState 方法,也即是说函数式组件没有 state,所以也可以被称作是无状态组件

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

组件传值

父组件传子组件

  • 通过在子组件写props,子组件再从this.props 中获取相应的值
// 父组件
class Parent extends React.Component {
    name = "张德帅";
    render() {
        return (
            <Child myProp={this.message} />
        );
    }
}

// 子组件
class Child extends React.Component {
    child_name = this.props.myProp;
    render(){
        return (
            <div>{this.child_name}</div>
        )
    }
}

子组件向父组件传值

子组件调用父组件通过 props 传入的处理函数,对需要传递的值进行处理

// 父组件
class Parent extends React.Component {
  state = {
    message:"张德帅"
  }

  handleMsg(msg){
    this.setState({
      message:msg
    })
  }

  render() {
    return (
      <>
        {this.state.message}
        <Child onMsg={(msg) => this.handleMsg(msg)}></Child>
      </>
    );
  }
}

// 子组件
class Child extends React.Component{
    handleClick(){
        this.props.onMsg("Hello");
    }
    render() {
        return (
            <button onClick={() => this.handleClick()}>Click me</button>
        );
    }
}

同级传递

状态提升,以父组件作为媒介,让兄弟组件通过父组件进行传递

// 父组件
class Parent extends React.Component {
  state = {
    message:"张德帅"
  }

  handleMsg(msg){
    this.setState({
      message:msg
    })
  }

  render() {
    return (
      <>
        {this.state.message}
        <Hello name={this.state.message}></Hello>
        <Child onChangeMsg={(msg) => this.handleMsg(msg)}></Child>
      </>
    );
  }
}

// 子组件 -- 发起改变的组件
class Child extends React.Component{
    render() {
        return (
            <button onClick={() => this.props.onChangeMsg("朱大常")}>Click me (朱大常)</button>
        );
    }
}

// 子组件 被改变的组件
class Hello extends React.Component{
    render(){
        return <h1>hello {this.props.name}</h1>
    }
}

通过refs-转发-子组件向父组件传值

class Parent extends React.Component {
  myRef = React.createRef();
  handleClickRef(msg) {
    this.myRef.current.innerText = msg;
  }

  render() {
    return (
      <>
        <RefsValue ref={this.myRef} handleClickRef={this.handleClickRef.bind(this)}></RefsValue>
      </>
    );
  }
}

// 子组件
const RefsValue = React.forwardRef((props, ref) => {
    return (<>
        <span ref={ref}>hello</span>
        <button
            onClick={() => props.handleClickRef('world')}
        >Change</button>
    </>);
});

孙组件传递context

第一步:在src创建文件 context.js(任意名)

context.js 内容如下

import { createContext } from "react";

export default createContext();

第二步:引用 使用 Provider包裹组件

// 父组件
import * as React from "react";
import Child from "./component/Child/Child";
import contextName from "./context/context";
class App extends React.Component {
  render(){
    return (
      <>
        <contextName.Provider value="dark">
          <Child></Child>
        </contextName.Provider>
      </>
    )
  }
}

export default App;

中间组件

// 中间组件
import * as React from "react";
import Child2 from "../Child2/Child";
class Child extends React.Component{
    render() {
        return (
            <>
            <h1>Child----0</h1>
            <Child2></Child2>
            </>
        );
    }
}

export default Child

孙组件使用 this.context 获取

// 孙组件
import React from "react";
import contextName from "../../context/context";

class Child2 extends React.Component{
    static contextType = contextName;
    render(){
        return (
            <div>
                <h1>child --- 1</h1>
                <button theme={this.context}>{this.context}</button>
            </div>
        )
    }
}

export default Child2

组合式组件props.children

概念:vue中的slot插槽一样

class App extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      name:"张德帅"
    }
  }
  render(){
    return (
      <>
        <SplitPane left={test1(this.state)} right={test2()}></SplitPane>
      </>
    )
  }
}

function test1(props111){
  return (
    <p>test-left {props111.name}</p>
  )
}

function test2(){
  return(
    <p>test-right</p>
  )
}

Hook

Hook 是 React 16.8 它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性

useLayoutEffect

但它会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染

总结:

  • 作用 例如测量布局
  • useLayoutEffect 相比 useEffect,通过同步执行状态更新可解决一些特性场景下的页面闪烁问题。
  • useEffect 可以满足百分之99的场景,而且 useLayoutEffect 会阻塞渲染,请谨慎使用。

useEffect

你可以把 useEffect Hook 看做 componentDidMountcomponentDidUpdatecomponentWillUnmount 这三个函数的组合。

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`;
  });

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

useState

import React, { useState } from "react";
function Counter() {
  const [count, setCount] = useState(0); // 第一个是 当前状态 第二个是让你更新它的函数
  const [todos, setTodos] = useState([{ test: "张德帅" }]);
  return (
    <div>
      <p>you clicked {count} times</p>
      <p>you name {todos[0].test}.</p>
      <button
        onClick={() => {
          setCount(count + 1);
        }}
      >
        click me
      </button>
      <button
        onClick={() => {
          setTodos((data) => {
            return [{ test: "asdqwe" }];
          });
        }}
      >
        change name
      </button>
    </div>
  );
}

export default Counter;

useContext

useContext(MyContext) 相当于 class 组件中的 static contextType = MyContext 或者 <MyContext.Consumer>

第一步 创建文件 context.js 和 class 组件一样

context.js 内容如下

import { createContext } from "react";

export default createContext();

第二步 父组件使用Provider包裹 然后使用value 传值

import * as React from "react";
import ThemeContext from "./context/context";
import Child01 from "./component/Child01";
const themes = {
  light: {
    foreground: "#000000",
    background: "#eeeeee"
  },
  dark: {
    foreground: "#ffffff",
    background: "#222222"
  }
};
function App(){
  return (
    <ThemeContext.Provider value={themes.dark}>
      <Child01></Child01>
    </ThemeContext.Provider>
  )
}

export default App;

第三步 中间组件


import Child02 from "../Child02/index";
function child01(){
    return (
        <Child02></Child02>
    )
}

export default child01;

第四步 孙组件 使用 useContext 获取值

import React, {useContext} from "react";
import ThemeContext from "../../context/context";
function Child02(){
    const theme = useContext(ThemeContext);
    return (
        <button style={{background:theme.background, color:theme.foreground}}>I am styled by theme context!</button>
    )
}

export default Child02;

useReducer

useState的替代方案,它接收一个形如 (state, action) => newStatereducer(瑞丢蛇-减速器),并返回当前的 state 以及与其配套的 dispatch(滴丝吧齐-调度) 方法

useReducer demo01


import React, {useReducer} from "react";

const initialState = {count:0};

function reducer(state, action){
    switch(action.type){
        case "increment":
            return {count:state.count + 1}
        case "decrement":
            return {count:state.count -1};
        default:
            throw new Error();
    }
}

function Reducerdemo01(){
    const [state, dispatch] = useReducer(reducer, initialState);
    return (
        <>
            count:{state.count}
            <button onClick={() => dispatch({type:"increment"})}>+</button>
            <button onClick={() => dispatch({type:"decrement"})}>-</button>
        </>
    )
}

export default Reducerdemo01;

useReducer demo02

import React, { useReducer } from "react";

const initState = {
    name:"",
    pwd:"",
    isLoading:false,
}

function loginReducer(state, action){
    switch(action.type){
        case "login":
            return {
                ...state,
                isLoading:true,
                name:"zhangds"
            }
        case "success":
            return{
                ...state,
                isLoading:false,
                name:"zhangds---ok",
                pwd:"123a"
            }
        case "error":
            return {
                ...state,
                isLoading: false,
                name:"zhangds---error"
            }
        default:
            return state;
    }
}

function Login(){
    const [state, dispatch] = useReducer(loginReducer, initState);
    const login = () =>{
        dispatch({type:"login"});
        setTimeout(() =>{
            dispatch({type:"success"});
        }, 2000)
    }

    return (
        <>
            <p>name:{state.name}</p>
            <p>pwd:{state.pwd}</p>
            <p>isLoading:{state.isLoading ? "真" :"假"}</p>
            <button onClick={login}>登录</button>
        </>
    )
}

export default Login;

useReducer 惰性

useCallback

useMemo

useRef

useImperativeHandle

useLayoutEffect

useDebugValue

posted @ 2022-02-21 11:20  半截肥皂  阅读(35)  评论(0编辑  收藏  举报