高阶组件
是一个函数,接收一个组件返回一个组件
function Child(props){
return <div>child- {props.name}</div>
}
const foo = Cmp => prpps =>{
return (
<Cmp {...props} />
)
}
class Hoc extends React.Component {
render(){
const Foo = foo(Child)
return (
<Foo name="aaa"/>
)
}
}
装饰器:高阶组件。不能是函数组件。
需要安装插件:@babel/plugin-proposal-decorators
用法:@组件
const foo = Cmp => prpps =>{
return (
<Cmp {...props} />
)
}
@foo
class Child extends React.Component{
render(){
retuen (
<div>{this.props.name}</div>
)
}
}
class Hoc extends React.Component {
render(){
return (
<Child name="aaa"/>
)
}
}
antd表单适用
import React, { Component } from "react";
import { Form, Button, Input } from "antd";
const nameRules = {
required: true,
message: "please input ur name"
};
const passwordRules = {
required: true,
message: "please input ur password"
};
@Form.create()
class FormPage extends Component {
submit = () => {
const { getFieldsValue, getFieldValue, validateFields } = this.props.form;
validateFields((err, values) => {
if (err) {
console.log("err", err);
} else {
console.log("success", values);
}
});
//console.log("submit", getFieldsValue(), getFieldValue("name"));
};
render() {
console.log("props", this.props);
const { getFieldDecorator } = this.props.form;
return (
<div>
<h3>FormPage</h3>
<Form>
<Form.Item label="用户名">
{getFieldDecorator("name", { rules: [nameRules] })(<Input />)}
</Form.Item>
<Form.Item label="密码">
{getFieldDecorator("password", { rules: [passwordRules] })(
<Input type="password" />
)}
</Form.Item>
</Form>
<Button onClick={this.submit}>submit</Button>
</div>
);
}
}
export default FormPage;
表单组件设计思路
1.表单组件要求实现数据收集,校验,提交等,可通过高阶组件扩展
2.高阶组件给表单组件传递一个input组件包装函数接管其输入事件并统一管理表单数据
3.高阶组件给表单组件传递一个校验函数使其具备数据校验功能。
自定义基础表单组件
// MyForm.js
import React, { Component } from "react";
import FormCreate from "../components/FormCreate";
const nameRules = {
required: true,
message: "please input your name"
};
const passwordRules = {
required: true,
message: "please input your password"
};
@FormCreate
class MyFormPage extends Component {
submit = () => {
const { getFieldsValue, getFieldValue, validateFields } = this.props;
validateFields((err, values) => {
if (err) {
console.log("err", err);
} else {
console.log("success", values);
}
});
// console.log("submit", getFieldsValue(), getFieldValue("name"));
};
render() {
console.log("props", this.props);
const { getFieldDecorator } = this.props;
return (
<div>
<h3>MyFormPage</h3>
{getFieldDecorator("name", { rules: [nameRules] })(<input />)}
{getFieldDecorator("password", { rules: [passwordRules] })(
<input type="password" />
)}
<button onClick={this.submit}>submit</button>
</div>
);
}
}
export default MyFormPage;
// FormCreate.js
import React, { useState } from "react";
const FormCreate = Cmp => props => {
const [state, setState] = useState({});
const options = {};
const setChange = event => {
setState({
...state,
[event.target.name]: event.target.value
});
};
const getFieldDecorator = (field, option) => InputCmp => {
options[field] = option;
return React.cloneElement(InputCmp, {
name: field,
value: state[field] || "",
onChange: setChange
});
};
const getFieldsValue = () => {
return { ...state };
};
const getFieldValue = field => {
return state[field];
};
const validateFields = callback => {
const err = [];
for (let key in options) {
if (state[key] === undefined) {
err.push({
[key]: "error!"
});
}
}
if (err.length) {
callback(err, { ...state });
} else {
callback(undefined, { ...state });
}
};
return (
<Cmp
{...props}
getFieldDecorator={getFieldDecorator}
getFieldsValue={getFieldsValue}
getFieldValue={getFieldValue}
validateFields={validateFields}
/>
);
};
export default FormCreate;
reducer
reducer 就是一个纯函数,接收旧的 state 和 action,返回新的state
(previousState, action) => newState
思考:有如下函数, 聚合成一个函数,并把第一个函数的返回值传递给下一个函数,如何处理。
function f1(arg){return arg}
function f2(arg){return arg}
function f3(arg){return arg}
方法:
function compose(...funcs) {
const len = funcs.length;
if (len === 0) {
return arg => arg;
}
if (len === 1) {
return funcs[0];
}
return funcs.reduce((a, b) => (...args) => a(b(...args)));
}
redux
1.需要一个store来存储数据
2.store里的reducer初始化state并定义state修改规则
3.通过dispatch一个action来提交对数据的修改
4.action提交到reducer函数里,根据传入的action的type,返回新的state
下面以累加器为例:
1.创建store,src/store/ReduxStore.js
import { createStore } from 'redux';
function counterReducer(state = 0, action) {
switch (action.type) {
case "add":
return state + 1;
case "minus":
return state - 1;
default:
return state;
}
}
const store = createStore(counterReducer) // createStore 第一个参数接收reducer
export default store;
2.创建ReduxPage
import React, { Component } from "react";
import store from "../store/";
export default class ReduxPage extends Component {
componentDidMount() {
// subscribe监听
store.subscribe(() => {
this.forceUpdate();
});
}
minus = () => {
store.dispatch({ type: "minus" });
};
add = () => {
store.dispatch({ type: "add" });
};
render() {
console.log("store", store);
return (
<div>
<h3>ReduxPage</h3>
<p>{store.getState()}</p>
<button onClick={this.add}>add</button>
<button onClick={this.minus}>minus</button>
</div>
);
}
}
3.通过上面即可实现了累加器
redux使用注意点:
- createStore 创建store
- reducer 初始化、修改状态函数
- getState 获取状态值
- dispatch 提交更新
- subscribe 变更订阅
自己实现一个redux
核心实现:
- 存储状态state
- 获取状态getState
- 更新状态dispatch
- 变更订阅subscribe
实现:
export function createStore(reducer, enhancer) {
// enhancer:中间件
if (enhancer) {
return enhancer(createStore)(reducer);
}
let currentState = undefined; // 初始状态
const listeners = []; // 接收多个监听函数
// 返回当前state即可
function getState() {
return currentState;
}
function dispatch(action) {
currentState = reducer(currentState, action); // 返回新的状态
listeners.map(listener => listener()); // 执行回调函数
}
// subscribe:接收一个回调函数,可能会监听多个。
function subscribe(listener) {
listeners.push(listener);
}
dispatch({ type: "curry_fe" }); // 初始化
return {
getState,
dispatch,
subscribe
};
}
redux实现异步
redux默认只支持同步,如果需要支持异步,比如ajax。需要中间件支持。
中间件:一个函数,对store.dispatch升级。在发出action和执行reducer中间,添加其他功能。
以redux-thunk和redux-logger为例:
npm i redux-thunk redux-logger -S
使用中间件:
import { createStore, applyMiddleware } from "redux";
import logger from 'redux-logger';
import thunk from 'redux-thunk';
const store = createStore(reducer,applyMiddleware(thunk,logger))
在异步操作的时候使用:
const asyncAdd = () => {
store.dispatch(() => {
setTimeout(() => {
// 异步结束后,执行dispatch
dispatch({
type:'asyncAdd'
})
},1000)
})
}
<button onClick={this.asyncAdd}>异步增加</button>
自己实现中间件
核心:实现函数序列执行
实现:
export function applyMiddleware(...middlewares) {
return createStore => (...args) => {
const store = createStore(...args);
let dispatch = store.dispatch;
const midAPi = {
getState: store.getState,
dispatch
};
const chain = middlewares.map(mw => mw(midAPi));
dispatch = compose(...chain)(dispatch);
return { ...store, dispatch };
};
}
function compose(...funcs) {
const len = funcs.length;
if (len === 0) {
return arg => arg;
}
if (len === 1) {
return funcs[0];
}
return funcs.reduce((a, b) => (...args) => a(b(...args)));
}
实现logger中间件
function logger() {
return dispatch => action => {
console.log(action.type + "执行了!");
return dispatch(action);
};
}
实现thunk中间件
function thunk() {
return dispatch => action => {
if (typeof action === "function") {
return action(dispatch);
}
return dispatch(action);
};
}