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 (
{fruits.map((item, index) => (
- {
onSelectF(item);
}}
key={index}
>
{item}
))}
);
}
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 (
{
setFname(e.target.value);
}}
onKeyDown={onAddFruit}
/>
);
}
//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 (
{ fruits, dispatch }}
{fruit === "" ? "请选择喜欢的水果" : `你选择的水果是${fruit}`}
);
}
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()
);
表单组件设计
是高阶组件工厂的实现,来强化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 (
{getFieldDecorator("userName", {
rules: [{ required: true, message: "Please input your username!" }]
})(
{ color: "rgba(0,0,0,.25)" }} /}
placeholder="Username"
/
)}
{getFieldDecorator("password", {
rules: [{ required: true, message: "Please input your Password!" }]
})(
{ color: "rgba(0,0,0,.25)" }} /}
type="password"
placeholder="Password"
/
)}
Login
);
}
}
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 (
{/* //vdom obj */}
{React.cloneElement(InputComp, {
name: field,
value: this.state[field] || "",
onChange: this.handleChange
})}
);
};
};
render() {
return (
);
}
};
}
class KForm extends Component {
submitTest = () => {
this.props.validateFields();
};
render() {
const { getFieldDecorator } = this.props;
return (
{/* 原来input 能力很弱,不知道收集用户信息 */}
{getFieldDecorator("userName", {
rules: [{ required: true, message: "Please input your username!" }]
})()}
{getFieldDecorator("password", {
rules: [{ required: true, message: "Please input your password!" }]
})()}
登录
);
}
}
const WidthForm = KFormCreate(KForm);
export default WidthForm;