举个栗子:react
接收函数做为参数webpack
function a(x) { x(); } function b() { alert('hello'); } a(b);
将函数做为输出返回git
function a() { function b() { alert('hello'); } return b; } a()();
以上函数a就是一个高阶函数, 用法很是简单, 那么实际开发中又有哪些是高阶函数呢?es6
举个栗子:github
// WrappedComponent 就是传入的包装组件 function withHoc(WrappedComponent) { return class extends Component { render () { return ( <WrappedComponent /> ) } } }
组件 Login -- 登录页面web
// 受控组件 class Login extends Component { state = { username: '', password: '' } onUsernameChange = (e) => { this.setState({username: e.target.value}); } onPasswordChange = (e) => { this.setState({password: e.target.value}); } login = (e) => { // 禁止默认事件 e.preventDefault(); // 收集表单数据 const { username, password } = this.state; alert(`用户名: ${username}, 密码: ${password}`); } render () { const { username, password } = this.state; return ( <div> <h2>登录</h2> <form onSubmit={this.login}> 用户名: <input type="text" name="username" value={username} onChange={this.onUsernameChange}/> <br/> 密码: <input type="password" name="password" value={password} onChange={this.onPasswordChange}/> <br/> <input type="submit" value="登录"/> </form> </div> ) } }
组件 Register -- 注册页面npm
// 受控组件 class Register extends Component { state = { username: '', password: '', rePassword: '' } onUsernameChange = (e) => { this.setState({username: e.target.value}); } onPasswordChange = (e) => { this.setState({password: e.target.value}); } onRePasswordChange = (e) => { this.setState({rePassword: e.target.value}); } register = (e) => { // 禁止默认事件 e.preventDefault(); // 收集表单数据 const { username, password, rePassword } = this.state; alert(`用户名: ${username}, 密码: ${password}, 确认密码: ${rePassword}`); } render () { const { username, password, rePassword } = this.state; return ( <div> <h2>注册</h2> <form onSubmit={this.register}> 用户名: <input type="text" name="username" value={username} onChange={this.onUsernameChange}/> <br/> 密码: <input type="password" name="password" value={password} onChange={this.onPasswordChange}/> <br/> 确认密码: <input type="password" name="rePassword" value={rePassword} onChange={this.onRePasswordChange}/> <br/> <input type="submit" value="注册"/> </form> </div> ) } }
咱们发现里面重复逻辑实在太多了,尤为是 onXxxChange 函数出现太多,咱们先优化一下。json
// 咱们以 Register 组件为例来看 class Register extends Component { state = { username: '', password: '', rePassword: '' } // 最终修改状态数据的函数 onChange = (stateName, stateValue) => { this.setState({[stateName]: stateValue}); } // 高阶函数 --> 这样后面就能一直复用当前函数,而不用从新建立了~ composeChange = (name) => { return (e) => this.onChange(name, e.target.value); } // 统一全部提交表单函数名 handleSubmit = (e) => { e.preventDefault(); const { username, password, rePassword } = this.state; alert(`用户名: ${username}, 密码: ${password}, 确认密码: ${rePassword}`); } render () { const { username, password, rePassword } = this.state; return ( <div> <h2>注册</h2> <form onSubmit={this.handleSubmit}> 用户名: <input type="text" name="username" value={username} onChange={this.composeChange('username')}/> <br/> 密码: <input type="password" name="password" value={password} onChange={this.composeChange('password')}/> <br/> 确认密码: <input type="password" name="rePassword" value={rePassword} onChange={this.composeChange('rePassword')}/> <br/> <input type="submit" value="注册"/> </form> </div> ) } }
如今两个页面都有 onChange 、 composeChange 、handleSubmit 函数和相关的状态,咱们接下来提取,封装成高阶组件!promise
// 高阶组件 withHoc export default function withHoc(WrappedComponent) { return class extends Component { state = { username: '', password: '', rePassword: '' } onChange = (stateName, stateValue) => { this.setState({[stateName]: stateValue}); } composeChange = (name) => { return (e) => this.onChange(name, e.target.value); } handleSubmit = (e) => { e.preventDefault(); const { username, password, rePassword } = this.state; if (rePassword) { alert(`用户名: ${username}, 密码: ${password}, 确认密码: ${rePassword}`); } else { alert(`用户名: ${username}, 密码: ${password}`); } } render () { // 抽取方法 const mapMethodToProps = { composeChange: this.composeChange, handleSubmit: this.handleSubmit, } // 将状态数据和操做的方法以 props 的方式传入的包装组件中 return ( <div> {/*提取公共头部*/} <h2>xxx</h2> <WrappedComponent {...this.state} {...mapMethodToProps}/> </div> ) } } } // 组件 Register class Register extends Component { render () { const { handleSubmit, composeChange, username, password, rePassword } = this.props; return ( <form onSubmit={handleSubmit}> 用户名: <input type="text" name="username" value={username} onChange={composeChange('username')}/> <br/> 密码: <input type="password" name="password" value={password} onChange={composeChange('password')}/> <br/> 确认密码: <input type="password" name="rePassword" value={rePassword} onChange={composeChange('rePassword')}/> <br/> <input type="submit" value="注册"/> </form> ) } } // 向外暴露的是高阶组件的返回值~包装了 Register 组件返回了一个新组件 export default withHoc(Register);
修改高阶组件babel
// 再次包裹了一层高阶函数, 这个高阶函数执行后返回值才是高阶组件 // 经过这种方式, 高阶组件内部就能获取参数了~ export default (title) => (WrappedComponent) => { return class Form extends Component { ...重复代码省略... render () { const mapMethodToProps = { composeChange: this.composeChange, handleSubmit: this.handleSubmit, } return ( <div> {/*获取到参数值就能正常显示了~*/} <h2>{title}</h2> <WrappedComponent {...this.state} {...mapMethodToProps}/> </div> ) } } }
在 Login / Register 组件中使用
修改 App 组件
class App extends Component { render() { return ( <div> {/*父组件向子组件传递属性*/} <Login name="jack" age={18}/> <Register /> </div> ); } }
修改高阶组件
export default (title) => (WrappedComponent) => { return class Form extends Component { ...重复代码省略... render () { const mapMethodToProps = { composeChange: this.composeChange, handleSubmit: this.handleSubmit, } return ( <div> {/*获取到参数值就能正常显示了~*/} <h2>{title}</h2> {/* 将当前组件接受到的props传给包装组件~*/} <WrappedComponent {...this.props} {...this.state} {...mapMethodToProps}/> </div> ) } } }
Login 组件中使用
class Login extends Component { render () { const { handleSubmit, composeChange, username, password, name, age } = this.props; return ( <div> <p>你的名字: {name}</p> <p>你的年龄: {age}</p> <form onSubmit={handleSubmit}> 用户名: <input type="text" name="username" value={username} onChange={composeChange('username')}/> <br/> 密码: <input type="password" name="password" value={password} onChange={composeChange('password')}/> <br/> <input type="submit" value="登录"/> </form> </div> ) } }
修改高阶组件
export default (title) => (WrappedComponent) => { return class Form extends Component { // 定义静态方法,修改组件在调试工具中显示的名称 static displayName = `Form(${getDisplayName(WrappedComponent)})` ...省略重复代码... } } // 获取包装组件的displayName的方法 function getDisplayName(WrappedComponent) { return WrappedComponent.displayName || WrappedComponent.name || 'Component'; }
下载包
在项目根目录配置 config-overrides.js
const { override, addDecoratorsLegacy } = require('customize-cra'); // 修改 create-react-app 的 webpack 的配置 module.exports = override( addDecoratorsLegacy() )
修改 package.json 的 scripts
// 将 react-scripts 修改成 react-app-rewired "scripts": { "start": "react-app-rewired start", "build": "react-app-rewired build", "test": "react-app-rewired test" },
修改 Login 组件
@withHoc('登录') class Login extends Component { ...省略重复代码... } export default Login;
修改 Register 组件
@withHoc('注册') class Register extends Component { ...省略重复代码... } export default Register;
重复代码永远是咱们须要考虑处理的代码,因此咱们有模块化、组件化、工具类函数等等,
在 React 中再次引入了一个高阶组件的概念,都是为了去除掉万恶的重复代码,让咱们代码变得更加精简。
本篇文章全部源码都放在了 git仓库,若是它对你有帮助的话,欢迎点 star ~~