React组件化二

29.9React课程

第03节:react组件化

第3节:react组件化

(Hooks&)

Hooks

Hooks本质就是一个函数

useState可以在函数组件初始化state

点击的时候,调用setName函数把name状态改为指定的值

可以创建多个useState

兄弟组件使用fragment来使用,直接在FruitsList解构{fruits}

setFruits是维护状态的函数

点击水果改变相应的状态,需要传递setFruit钩子来改变fruit属性

只要把最新的值传递给onSelectF即可

自身状态需要通过useState进行维护

用户输入完毕回车,调用onAdd来更新父组件的数组,e是用户输入的值

子组件传递值给Hooks,接收到值对自身数组进行维护,需要使用回调状态提升

拿到fname来调用setFruits,不能对原来state进行操作,需要对新的值进行覆盖。

import React, {
  Component,
  useState,
  useEffect,
  useContext,
  useReducer
} from "react";

function FruitsList({ fruits, onSelectF }) {
  return (
    <ul>
      {fruits.map((item, index) => (
        <li
          onClick={() => {
            onSelectF(item);
          }}
          key={index}
        >
          {item}
        </li>
      ))}
    </ul>
  );
}
const Context = React.createContext();

const { Provider } = Context;

function FruitAdd(props) {
  //用户输入水果,回车后水果列表添
  const [fname, setFname] = useState("");

  const { fruits, dispatch } = useContext(Context);
  const onAddFruit = e => {
    if (e.key === "Enter") {
      //   setFruits([...fruits, fname]);
      dispatch({ type: "add", newF: fname });
      setFname("");
    }
  };
  return (
    <div>
      <input
        type="text"
        value={fname}
        onChange={e => {
          setFname(e.target.value);
        }}
        onKeyDown={onAddFruit}
      />
    </div>
  );
}

//useReducer不是必须得选项,非必要时不建议使用
//把组件内部的状态抽离到外部统一处理

function FruitReducer(state, action) {
  console.log(state, action);
  switch (action.type) {
    case "init":
      return action.arr;
    case "add":
      return [...state, action.newF];
    default:
      return state;
  }
}

function HooksTest() {
  //useState会返回一个数组,里面有状态以及维护状态的函数
  const [fruit, setFruit] = useState("草莓");

  //   const [fruits, setFruits] = useState(["草莓", "香蕉"]);

  const [fruits, dispatch] = useReducer(FruitReducer, []);

  useEffect(() => {
    setTimeout(() => {
      dispatch({ type: "init", arr: ["草莓", "香蕉"] });
    }, 2000);
  }, []);

  //第二个参数是依赖,依赖哪些state来触发effect
  //当是一个空数组时,只触发一次
  //清除副作用

  //didmount update unmount
  //   useEffect(() => {
  //     //ajax之类的请求
  //     const timer = setInterval(() => {
  //       console.log("1");

  //       setFruits(["草莓2", "香蕉2"]);
  //     }, 1000);

  //     //类组件里 有willunmount
  //     function clear() {
  //       clearInterval(timer);
  //     }
  //     return clear;
  //   }, []);

  //didmount 执行一次 useEffect 返回clear函数
  //组件卸载的时候 执行一次  clear 然后才是 useEffect里面的逻辑
  //clear
  //useEffect

  return (
    <>
      <Provider value={{ fruits, dispatch }}>
        <div>
          {fruit === "" ? "请选择喜欢的水果" : `你选择的水果是${fruit}`}
        </div>
        <FruitAdd />
        <FruitsList fruits={fruits} onSelectF={setFruit} />
      </Provider>
    </>
  );
}

export default HooksTest;

useEffect让函数组件拥有生命周期

useEffect接收一个回调,加载组件会首先执行一次useEffect如果自身状态改变还会触发一次effect,组件被销毁还要执行一次

如果状态频繁更新,钩子会频繁调用,第二个参数是一个依赖,只有依赖发生了改变才会进行触发

如果数组中没有任何值useEffect只会执行一次

状态发生改变会触发useEffect

销毁的时候执行一次,清除effect

设置空数组,状态的更新不会触发

组件卸载的时候,不会执行setInterval,先执行clear(),上次返回的clear之后才是里面逻辑

useContext获取上下文实现状态共享

拿到用户输入值进行状态提升

拿过来就可以在组件内部使用了,可以有多个Provider一定要确定自己接受的是哪一个状态

useContext会接收context实例,使用传递过来的值了。

不需要传递onAdd了,变为非常纯粹的标签,直接使用setFruits进行更新

useReducer并非非要使用的API,不建议使用,把组件内部的状态抽离到外部统一处理

定义reducer函数,dispatch由FruitReducer来接管的

action就是dispatch里面的对象,根据对象的类型来拓展

通过action传递参数

(AntD企业级UI第三方组件&)

AntD企业级UI第三方组件&

减少打包,按需加载功能

在根目录下创建config-overrides.js配置文件,实现按需加载

支持装饰器语法

config-overrides.js

const {
  override,
  fixBabelImports,
  addDecoratorsLegacy
} = require("customize-cra");

module.exports = override(
  fixBabelImports("import", {
    libraryName: "antd",
    libraryDirectory: "es",
    style: "css"
  }),
  addDecoratorsLegacy()
);

表单组件设计

<Form.item>是高阶组件工厂的实现,来强化input

import React from "react";
import { Form, Icon, Input, Button } from "antd";
import "antd/dist/antd.css";
class NormalLoginForm extends React.Component {
  handleSubmit = e => {
    e.preventDefault();
    this.props.form.validateFields((err, values) => {
      if (!err) {
        console.log("Received values of form: ", values);
      }
    });
  };

  render() {
    const { getFieldDecorator } = this.props.form;
    return (
      <Form onSubmit={this.handleSubmit} className="login-form">
        <Form.Item>
          {getFieldDecorator("userName", {
            rules: [{ required: true, message: "Please input your username!" }]
          })(
            <Input
              prefix={<Icon type="user" style={{ color: "rgba(0,0,0,.25)" }} />}
              placeholder="Username"
            />
          )}
        </Form.Item>
        <Form.Item>
          {getFieldDecorator("password", {
            rules: [{ required: true, message: "Please input your Password!" }]
          })(
            <Input
              prefix={<Icon type="lock" style={{ color: "rgba(0,0,0,.25)" }} />}
              type="password"
              placeholder="Password"
            />
          )}
        </Form.Item>
        <Form.Item>
          <Button
            type="primary"
            htmlType="submit"
            className="login-form-button"
          >
            Login
          </Button>
        </Form.Item>
      </Form>
    );
  }
}

const WrappedNormalLoginForm = Form.create({ name: "normal_login" })(
  NormalLoginForm
);

export default WrappedNormalLoginForm;

自己实现高阶工厂配置,KFormCreate接收一个组件返回一个组件,对KForm组件进行包装

getFieldDecorator接收字段名称与校验规则,返回hoc,接收一个组件返回一个加强的input组件

对接收到的input已经是vdom,在对象上进行属性的添加

handleChange具备收集用户数据能力,接收用户输入的值并传递到state中 

e.target获取用户输入的值value与字段name,通过动态计算的方式 在state上生成对应的username与password和对应的值

输入值不断触发validateField得到rule

点击登录直接触发validation()

import React, { Component } from "react";

function KFormCreate(Comp) {
  return class extends Component {
    constructor(props) {
      super(props);
      this.options = {};
      this.state = {};
    }

    handleChange = e => {
      // this.setState()
      let { name, value } = e.target;
      this.setState({ [name]: value }, () => {
        this.validateField(name);
      });
    };
    validateField = name => {
      //username
      //password
      const rule = this.options[name].rules;
      console.log(rule);
    };
    validateFields = () => {
      console.log("提交");
    };
    getFieldDecorator = (field, options) => {
      this.options[field] = options;
      return InputComp => {
        return (
          <div>
            {/* //vdom  obj */}
            {React.cloneElement(InputComp, {
              name: field,
              value: this.state[field] || "",
              onChange: this.handleChange
            })}
          </div>
        );
      };
    };

    render() {
      return (
        <Comp
          {...this.props}
          validateFields={this.validateFields}
          getFieldDecorator={this.getFieldDecorator}
        />
      );
    }
  };
}

class KForm extends Component {
  submitTest = () => {
    this.props.validateFields();
  };
  render() {
    const { getFieldDecorator } = this.props;
    return (
      <div>
        <div>
          {/* 原来input 能力很弱,不知道收集用户信息 */}
          {getFieldDecorator("userName", {
            rules: [{ required: true, message: "Please input your username!" }]
          })(<input type="text" />)}
        </div>
        <div>
          {getFieldDecorator("password", {
            rules: [{ required: true, message: "Please input your password!" }]
          })(<input type="password" />)}
        </div>
        <div>
          <button onClick={this.submitTest}>登录</button>
        </div>
      </div>
    );
  }
}
const WidthForm = KFormCreate(KForm);

export default WidthForm;

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wespten

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值