react基础---组件02

目录
1. Hook
  1.1 状态钩子 - State Hook 
    useState
  1.2 副作用钩子 - Effffect Hook
    原理
    渲染即调用、一次调用、某种状态下调用
  1.3 自定义钩子 - Custom Hook
    多组件调用同一个
  1.4 其他Hook
2. 组件跨层级通信 - Context
  Context相关API
  3种方法组件通信
3. 组件设计与实现
表单组件实现

内容

1. Hook
  主要应用于函数组件,解决函数组件没有状态和生命周期的问题。
1.1 状态钩子 - State Hook 
  [state, setState] = useState(init),useState函数传入参数init,返回值是数组,数组内 [state状态, setState修改状态]
import React, { useState } from "react";

export default function HookTest() {
  // useState(initState)
  const [count, setCount] = useState(0);
  // 多个状态
  const age = useAge();
  const [fruit, setFruit] = useState("banana");
  const [input, setInput] = useState("");
  const [fruits, setFruits] = useState(["apple", "banana"]);

  return (
    <div>
      <p>点击了{count}次</p>
      <button onClick={() => setCount(count + 1)}>点击</button>

      <p>年龄:{age ? age : 'loading...'}</p>
      <p>选择的水果:{fruit}</p>
      <p>
        <input
          type="text"
          value={input}
          onChange={e => setInput(e.target.value)}
        />
        <button onClick={() => setFruits([...fruits, input])}>新增水果</button>
      </p>
      <ul>
        {fruits.map(f => (
          <li key={f} onClick={() => setFruit(f)}>
            {f}
          </li>
        ))}
      </ul>
    </div>
  );
}
View Code
1.2 副作用钩子 - Effffect Hook
  原理:给函数组件增加操作副作用的能力。具有componentDidMounted、componentDidUpdate、componentDidDestroy三个生命周期相同的功能。
  渲染即调用、一次调用()、某种状态下调用
  useEffect(fn, []),每次渲染执行useEffect函数;第二个参数控制什么时候执行,如果是空数组,则执行一次,类似componentDidMounted;第二个参数[count, fill], 当只有在count或fill修改的情况下才执行函数useEffect。
import React, { useState, useEffect } from "react";

export default function HookTest() {
  // useState(initState)
  const [count, setCount] = useState(0);

  // 副作用钩子会在每次渲染时都执行,每次count修改才会执行
  useEffect(() => {
    document.title = `您点击了${count}次`;
  }, [count]);

  //   如果仅打算执行一次,传递第二个参数为[]
  //   componentDidMount
  useEffect(() => {
    // api调用
    console.log("api调用");
  }, []);

  return (
    <div>
      <p>点击了{count}次</p>
      <button onClick={() => setCount(count + 1)}>点击</button>
    </div>
  );
}
View Code
1.3 自定义钩子 - Custom Hook
  多组件调用同一个
import React, { useState, useEffect } from "react";

// 自定义hook是一个函数,名称用“use"开头,函数内部可以调用其他钩子
function useAge() {
  const [age, setAge] = useState(0);
  useEffect(() => {
    setTimeout(() => {
      setAge(20);
    }, 2000);
  });
  return age;
}

export default function HookTest() {
  // const [age] = useState("0");
  const age = useAge();

  return (
    <div>
      <p>年龄:{age ? age : 'loading...'}</p>
    </div>
  );
}
View Code
1.4 其他Hook
  useContext、useReducer、useCallBack、useMemo
  useCallBack、useMemo类似vue中的computed计算属性
2. 组件跨层级通信 - Context
2.1 Context相关API
  React.createContext
  Context.Provider
  Context.Comsumer
  Class.contentType
2.2 3种方法组件通信
import React, { useContext } from "react";

// 1.创建上下文
const MyContext = React.createContext();
const { Provider, Consumer } = MyContext;

function Child(prop) {
  return <div>Child: {prop.foo}</div>;
}
// 2.使用hook消费
function Child2() {
  const context = useContext(MyContext);
  return <div>Child2: {context.foo}</div>;
}
// 3. 使用class指定静态contextType
class Child3 extends React.Component {
    // 设置静态属性通知编译器获取上下文中数据并赋值给this.context
    static contextType = MyContext;
    render() {
        return <div>Child3: {this.context.foo}</div>
    }
}
export default function ContextTest() {
  return (
    <div>
      <Provider value={{ foo: "bar" }}>
        {/* 消费方法1:Consumer */}
        <Consumer>{value => <Child {...value} />}</Consumer>
        {/* 消费方法2:hook */}
        <Child2 />
        {/* 消费方法3:contextType */}
        <Child3 />
      </Provider>
    </div>
  );
}
View Code
3. 组件设计与实现
表单组件实现
import React from "react";
import { Input, Button } from "antd";

// 创建一个高阶组件:扩展现有表单,事件处理、数据收集、校验
function kFormCreate(Comp) {
  return class extends React.Component {
    constructor(props) {
      super(props);

      this.options = {};
      this.state = {};
    }

    handleChange = e => {
      const { name, value } = e.target;
      console.log(name, value);

      this.setState({ [name]: value }, () => {
        //   确保值发生变化再校验
        this.validateField(name);
      });
    };

    // 单项校验
    validateField = field => {
      // 1. 获取校验规则
      const rules = this.options[field].rules;
      // 任意一项失败则返回false
      const ret = !rules.some(rule => {
        if (rule.required) {
          if (!this.state[field]) {
            //校验失败
            this.setState({
              [field + "Message"]: rule.message
            });
            return true;
          }
        }
      });

      if (ret) { // 校验成功
        this.setState({
          [field + "Message"]: ""
        });
      }
      return ret;
    };

    // 校验所有字段
    validate = cb => {
      const rets = Object.keys(this.options).map(field =>
        this.validateField(field)
      );

      const ret = rets.every(v => v == true);
      cb(ret, this.state);
    };

    // 创建input包装器
    getFieldDec = (field, option) => {
      // 保存当前输入项配置
      this.options[field] = option;
      return InputComp => (
        <div>
          {React.cloneElement(InputComp, {
            name: field,
            value: this.state[field] || "",
            onChange: this.handleChange
          })}
          {/* 校验错误信息 */}
          {this.state[field+'Message'] && (
              <p style={{color:'red'}}>{this.state[field+'Message']}</p>
          )}
        </div>
      );
    };

    render() {
      return <Comp getFieldDec={this.getFieldDec} validate={this.validate} />;
    }
  };
}

@kFormCreate
class KForm extends React.Component {
  onSubmit = () => {
    console.log("submit");
    // 校验所有项
    this.props.validate((isValid, data) => {
      if (isValid) {
        //提交登录
        console.log("登录:", data);
        // 后续登录逻辑
      } else {
        alert("校验失败");
      }
    });
  };

  render() {
    const { getFieldDec } = this.props;
    return (
      <div>
        {getFieldDec("uname", {
          rules: [{ required: true, message: "用户名必填" }]
        })(<Input />)}

        {getFieldDec("pwd", {
          rules: [{ required: true, message: "密码必填" }]
        })(<Input type="password" />)}

        <Button onClick={this.onSubmit}>登录</Button>
      </div>
    );
  }
}

export default KForm;
View Code
原文地址:https://www.cnblogs.com/shaokevin/p/12259789.html