如何配置 React-Router 实现路由切换

(1)应用<Route> 组件

路由匹配是通过比拟 <Route> 的 path 属性和以后地址的 pathname 来实现的。当一个 <Route> 匹配胜利时,它将渲染其内容,当它不匹配时就会渲染 null。没有门路的 <Route> 将始终被匹配。

// when location = { pathname: '/about' }<Route path='/about' component={About}/> // renders <About/><Route path='/contact' component={Contact}/> // renders null<Route component={Always}/> // renders <Always/>

(2)联合应用 <Switch> 组件和 <Route> 组件

<Switch> 用于将 <Route> 分组。

<Switch>    <Route exact path="/" component={Home} />    <Route path="/about" component={About} />    <Route path="/contact" component={Contact} /></Switch>

<Switch> 不是分组 <Route> 所必须的,但他通常很有用。 一个 <Switch> 会遍历其所有的子 <Route>元素,并仅渲染与以后地址匹配的第一个元素。

(3)应用 <Link>、 <NavLink>、<Redirect> 组件

<Link> 组件来在你的应用程序中创立链接。无论你在何处渲染一个<Link> ,都会在应用程序的 HTML 中渲染锚(<a>)。

<Link to="/">Home</Link>   // <a href='/'>Home</a>

是一种非凡类型的 当它的 to属性与以后地址匹配时,能够将其定义为"沉闷的"。

// location = { pathname: '/react' }<NavLink to="/react" activeClassName="hurray">    React</NavLink>// <a href='/react' className='hurray'>React</a>

当咱们想强制导航时,能够渲染一个<Redirect>,当一个<Redirect>渲染时,它将应用它的to属性进行定向。

refs的作用是什么,你在什么样的业务场景下应用refs

  • 操作DOM,为什么操作DOM?
  • 场景

    • 图片渲染好后,操作图片宽高。比方做个放大镜性能

React组件命名举荐的形式是哪个?

通过援用而不是应用来命名组件displayName。

应用displayName命名组件:

export default React.createClass({  displayName: 'TodoApp',  // ...})

React举荐的办法:

export default class TodoApp extends React.Component {  // ...}

当渲染一个列表时,何为 key?设置 key 的目标是什么

Keys 会有助于 React 辨认哪些 items 扭转了,被增加了或者被移除了。Keys 应该被赋予数组内的元素以赋予(DOM)元素一个稳固的标识,抉择一个 key 的最佳办法是应用一个字符串,该字符串能惟一地标识一个列表项。很多时候你会应用数据中的 IDs 作为 keys,当你没有稳固的 IDs 用于被渲染的 items 时,能够应用我的项目索引作为渲染项的 key,但这种形式并不举荐,如果 items 能够从新排序,就会导致 re-render 变慢。

Redux 和 Vuex 有什么区别,它们的独特思维

(1)Redux 和 Vuex区别

  • Vuex改良了Redux中的Action和Reducer函数,以mutations变动函数取代Reducer,无需switch,只需在对应的mutation函数里扭转state值即可
  • Vuex因为Vue主动从新渲染的个性,无需订阅从新渲染函数,只有生成新的State即可
  • Vuex数据流的程序是∶View调用store.commit提交对应的申请到Store中对应的mutation函数->store扭转(vue检测到数据变动主动渲染)

艰深点了解就是,vuex 弱化 dispatch,通过commit进行 store状态的一次更变;勾销了action概念,不用传入特定的 action模式进行指定变更;弱化reducer,基于commit参数间接对数据进行转变,使得框架更加繁难;

(2)独特思维

  • 单—的数据源
  • 变动能够预测

实质上∶ redux与vuex都是对mvvm思维的服务,将数据从视图中抽离的一种计划。

为什么调用 setState 而不是间接扭转 state?

解答

如果您尝试间接扭转组件的状态,React 将无奈得悉它须要从新渲染组件。通过应用setState()办法,React 能够更新组件的UI。

另外,您还能够谈谈如何不保障状态更新是同步的。如果须要基于另一个状态(或属性)更新组件的状态,请向setState()传递一个函数,该函数将 state 和 props 作为其两个参数:

this.setState((state, props) => ({  counter: state.counter + props.increment}));

React-Router的实现原理是什么?

客户端路由实现的思维:

  • 基于 hash 的路由:通过监听hashchange事件,感知 hash 的变动

    • 扭转 hash 能够间接通过 location.hash=xxx
  • 基于 H5 history 路由:

    • 扭转 url 能够通过 history.pushState 和 resplaceState 等,会将URL压入堆栈,同时可能利用 history.go() 等 API
    • 监听 url 的变动能够通过自定义事件触发实现

react-router 实现的思维:

  • 基于 history 库来实现上述不同的客户端路由实现思维,并且可能保留历史记录等,磨平浏览器差别,下层无感知
  • 通过保护的列表,在每次 URL 发生变化的回收,通过配置的 路由门路,匹配到对应的 Component,并且 render

参考:前端react面试题具体解答

React申明组件有哪几种办法,有什么不同?

React 申明组件的三种形式:

  • 函数式定义的无状态组件
  • ES5原生形式React.createClass定义的组件
  • ES6模式的extends React.Component定义的组件

(1)无状态函数式组件 它是为了创立纯展现组件,这种组件只负责依据传入的props来展现,不波及到state状态的操作
组件不会被实例化,整体渲染性能失去晋升,不能拜访this对象,不能拜访生命周期的办法

(2)ES5 原生形式 React.createClass // RFC React.createClass会自绑定函数办法,导致不必要的性能开销,减少代码过期的可能性。

(3)E6继承模式 React.Component // RCC 目前极为举荐的创立有状态组件的形式,最终会取代React.createClass模式;绝对于 React.createClass能够更好实现代码复用。

无状态组件绝对于于后者的区别: 与无状态组件相比,React.createClass和React.Component都是创立有状态的组件,这些组件是要被实例化的,并且能够拜访组件的生命周期办法。

React.createClass与React.Component区别:

① 函数this自绑定

  • React.createClass创立的组件,其每一个成员函数的this都有React主动绑定,函数中的this会被正确设置。
  • React.Component创立的组件,其成员函数不会主动绑定this,须要开发者手动绑定,否则this不能获取以后组件实例对象。

② 组件属性类型propTypes及其默认props属性defaultProps配置不同

  • React.createClass在创立组件时,无关组件props的属性类型及组件默认的属性会作为组件实例的属性来配置,其中defaultProps是应用getDefaultProps的办法来获取默认组件属性的
  • React.Component在创立组件时配置这两个对应信息时,他们是作为组件类的属性,不是组件实例的属性,也就是所谓的类的动态属性来配置的。

③ 组件初始状态state的配置不同

  • React.createClass创立的组件,其状态state是通过getInitialState办法来配置组件相干的状态;
  • React.Component创立的组件,其状态state是在constructor中像初始化组件属性一样申明的。

Redux 怎么实现属性传递,介绍下原理

react-redux 数据传输∶ view-->action-->reducer-->store-->view。看下点击事件的数据是如何通过redux传到view上:

  • view 上的AddClick 事件通过mapDispatchToProps 把数据传到action ---> click:()=>dispatch(ADD)
  • action 的ADD 传到reducer上
  • reducer传到store上 const store = createStore(reducer);
  • store再通过 mapStateToProps 映射穿到view上text:State.text

代码示例∶

import React from 'react';import ReactDOM from 'react-dom';import { createStore } from 'redux';import { Provider, connect } from 'react-redux';class App extends React.Component{    render(){        let { text, click, clickR } = this.props;        return(            <div>                <div>数据:已有人{text}</div>                <div onClick={click}>加人</div>                <div onClick={clickR}>减人</div>            </div>        )    }}const initialState = {    text:5}const reducer = function(state,action){    switch(action.type){        case 'ADD':            return {text:state.text+1}        case 'REMOVE':            return {text:state.text-1}        default:            return initialState;    }}let ADD = {    type:'ADD'}let Remove = {    type:'REMOVE'}const store = createStore(reducer);let mapStateToProps = function (state){    return{        text:state.text    }}let mapDispatchToProps = function(dispatch){    return{        click:()=>dispatch(ADD),        clickR:()=>dispatch(Remove)    }}const App1 = connect(mapStateToProps,mapDispatchToProps)(App);ReactDOM.render(    <Provider store = {store}>        <App1></App1>    </Provider>,document.getElementById('root'))

为什么应用jsx的组件中没有看到应用react却须要引入react?

实质上来说JSX是React.createElement(component, props, ...children)办法的语法糖。在React 17之前,如果应用了JSX,其实就是在应用React, babel 会把组件转换为 CreateElement 模式。在React 17之后,就不再须要引入,因为 babel 曾经能够帮咱们主动引入react。

应该在 React 组件的何处发动 Ajax 申请

在 React 组件中,应该在 componentDidMount 中发动网络申请。这个办法会在组件第一次“挂载”(被增加到 DOM)时执行,在组件的生命周期中仅会执行一次。更重要的是,你不能保障在组件挂载之前 Ajax 申请曾经实现,如果是这样,也就意味着你将尝试在一个未挂载的组件上调用 setState,这将不起作用。在 componentDidMount 中发动网络申请将保障这有一个组件能够更新了。

react16的谬误边界(Error Boundaries)是什么

局部 UI 中的 JavaScript 谬误不应该毁坏整个应用程序。 为了解决 React 用户的这个问题,React 16引入了一个 “谬误边界(Error Boundaries)” 的新概念。

import React from 'react';import ReactDOM from 'react-dom';class ErrorBoundary extends React.Component{    constructor(props) {        super(props);        this.state={hasError:false};    }    componentDidCatch(err,info) {        this.setState({hasError: true});    }    render() {        if (this.state.hasError) {            return <h1>Something Went Wrong</h1>        }        return this.props.children;    }}class Page extends React.Component{    render() {        return (            <ErrorBoundary>                <Clock/>            </ErrorBoundary>        )    }}class Clock extends React.Component{    render() {        return (            <div>hello{null.toString()}</div>        )    }}ReactDOM.render(<Page/>,document.querySelector('#root'));

对React-Fiber的了解,它解决了什么问题?

React V15 在渲染时,会递归比对 VirtualDOM 树,找出须要变动的节点,而后同步更新它们, 零打碎敲。这个过程期间, React 会占据浏览器资源,这会导致用户触发的事件得不到响应,并且会导致掉帧,导致用户感觉到卡顿

为了给用户制作一种利用很快的“假象”,不能让一个工作长期霸占着资源。 能够将浏览器的渲染、布局、绘制、资源加载(例如 HTML 解析)、事件响应、脚本执行视作操作系统的“过程”,须要通过某些调度策略正当地调配 CPU 资源,从而进步浏览器的用户响应速率, 同时兼顾工作执行效率。

所以 React 通过Fiber 架构,让这个执行过程变成可被中断。“适时”地让出 CPU 执行权,除了能够让浏览器及时地响应用户的交互,还有其余益处:

  • 分批延时对DOM进行操作,防止一次性操作大量 DOM 节点,能够失去更好的用户体验;
  • 给浏览器一点喘息的机会,它会对代码进行编译优化(JIT)及进行热代码优化,或者对 reflow 进行修改。

核心思想: Fiber 也称协程或者纤程。它和线程并不一样,协程自身是没有并发或者并行能力的(须要配合线程),它只是一种管制流程的让出机制。让出 CPU 的执行权,让 CPU 能在这段时间执行其余的操作。渲染的过程能够被中断,能够将控制权交回浏览器,让位给高优先级的工作,浏览器闲暇后再复原渲染。

React的事件和一般的HTML事件有什么不同?

区别:

  • 对于事件名称命名形式,原生事件为全小写,react 事件采纳小驼峰;
  • 对于事件函数解决语法,原生事件为字符串,react 事件为函数;
  • react 事件不能采纳 return false 的形式来阻止浏览器的默认行为,而必须要地明确地调用preventDefault()来阻止默认行为。

合成事件是 react 模仿原生 DOM 事件所有能力的一个事件对象,其长处如下:

  • 兼容所有浏览器,更好的跨平台;
  • 将事件对立寄存在一个数组,防止频繁的新增与删除(垃圾回收)。
  • 不便 react 对立治理和事务机制。

事件的执行程序为原生事件先执行,合成事件后执行,合成事件会冒泡绑定到 document 上,所以尽量避免原生事件与合成事件混用,如果原生事件阻止冒泡,可能会导致合成事件不执行,因为须要冒泡到document 上合成事件才会执行。

Redux 原理及工作流程

(1)原理 Redux源码次要分为以下几个模块文件

  • compose.js 提供从右到左进行函数式编程
  • createStore.js 提供作为生成惟一store的函数
  • combineReducers.js 提供合并多个reducer的函数,保障store的唯一性
  • bindActionCreators.js 能够让开发者在不间接接触dispacth的前提下进行更改state的操作
  • applyMiddleware.js 这个办法通过中间件来加强dispatch的性能
const actionTypes = {    ADD: 'ADD',    CHANGEINFO: 'CHANGEINFO',}const initState = {    info: '初始化',}export default function initReducer(state=initState, action) {    switch(action.type) {        case actionTypes.CHANGEINFO:            return {                ...state,                info: action.preload.info || '',            }        default:            return { ...state };    }}export default function createStore(reducer, initialState, middleFunc) {    if (initialState && typeof initialState === 'function') {        middleFunc = initialState;        initialState = undefined;    }    let currentState = initialState;    const listeners = [];    if (middleFunc && typeof middleFunc === 'function') {        // 封装dispatch         return middleFunc(createStore)(reducer, initialState);    }    const getState = () => {        return currentState;    }    const dispatch = (action) => {        currentState = reducer(currentState, action);        listeners.forEach(listener => {            listener();        })    }    const subscribe = (listener) => {        listeners.push(listener);    }    return {        getState,        dispatch,        subscribe    }}

(2)工作流程

  • const store= createStore(fn)生成数据;
  • action: {type: Symble('action01), payload:'payload' }定义行为;
  • dispatch发动action:store.dispatch(doSomething('action001'));
  • reducer:解决action,返回新的state;

艰深点解释:

  • 首先,用户(通过View)收回Action,收回形式就用到了dispatch办法
  • 而后,Store主动调用Reducer,并且传入两个参数:以后State和收到的Action,Reducer会返回新的State
  • State—旦有变动,Store就会调用监听函数,来更新View

以 store 为外围,能够把它看成数据存储核心,然而他要更改数据的时候不能间接批改,数据批改更新的角色由Reducers来负责,store只做存储,中间人,当Reducers的更新实现当前会通过store的订阅来告诉react component,组件把新的状态从新获取渲染,组件中也能被动发送action,创立action后这个动作是不会执行的,所以要dispatch这个action,让store通过reducers去做更新React Component 就是react的每个组件。

React 高阶组件是什么,和一般组件有什么区别,实用什么场景

官网解释∶

高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 本身不是 React API 的一部分,它是一种基于 React 的组合个性而造成的设计模式。

高阶组件(HOC)就是一个函数,且该函数承受一个组件作为参数,并返回一个新的组件,它只是一种组件的设计模式,这种设计模式是由react本身的组合性质必然产生的。咱们将它们称为纯组件,因为它们能够承受任何动静提供的子组件,但它们不会批改或复制其输出组件中的任何行为。

// hoc的定义function withSubscription(WrappedComponent, selectData) {  return class extends React.Component {    constructor(props) {      super(props);      this.state = {        data: selectData(DataSource, props)      };    }    // 一些通用的逻辑解决    render() {      // ... 并应用新数据渲染被包装的组件!      return <WrappedComponent data={this.state.data} {...this.props} />;    }  };// 应用const BlogPostWithSubscription = withSubscription(BlogPost,  (DataSource, props) => DataSource.getBlogPost(props.id));

1)HOC的优缺点

  • 长处∶ 逻辑服用、不影响被包裹组件的外部逻辑。
  • 毛病∶hoc传递给被包裹组件的props容易和被包裹后的组件重名,进而被笼罩

2)实用场景

  • 代码复用,逻辑形象
  • 渲染劫持
  • State 形象和更改
  • Props 更改

3)具体利用例子

  • 权限管制: 利用高阶组件的 条件渲染 个性能够对页面进行权限管制,权限管制个别分为两个维度:页面级别和 页面元素级别
// HOC.jsfunction withAdminAuth(WrappedComponent) {    return class extends React.Component {        state = {            isAdmin: false,        }        async UNSAFE_componentWillMount() {            const currentRole = await getCurrentUserRole();            this.setState({                isAdmin: currentRole === 'Admin',            });        }        render() {            if (this.state.isAdmin) {                return <WrappedComponent {...this.props} />;            } else {                return (<div>您没有权限查看该页面,请分割管理员!</div>);            }        }    };}// pages/page-a.jsclass PageA extends React.Component {    constructor(props) {        super(props);        // something here...    }    UNSAFE_componentWillMount() {        // fetching data    }    render() {        // render page with data    }}export default withAdminAuth(PageA);// pages/page-b.jsclass PageB extends React.Component {    constructor(props) {        super(props);    // something here...        }    UNSAFE_componentWillMount() {    // fetching data    }    render() {    // render page with data    }}export default withAdminAuth(PageB);
  • 组件渲染性能追踪: 借助父组件子组件生命周期规定捕捉子组件的生命周期,能够不便的对某个组件的渲染工夫进行记录∶
class Home extends React.Component {        render() {            return (<h1>Hello World.</h1>);        }    }    function withTiming(WrappedComponent) {        return class extends WrappedComponent {            constructor(props) {                super(props);                this.start = 0;                this.end = 0;            }            UNSAFE_componentWillMount() {                super.componentWillMount && super.componentWillMount();                this.start = Date.now();            }            componentDidMount() {                super.componentDidMount && super.componentDidMount();                this.end = Date.now();                console.log(`${WrappedComponent.name} 组件渲染工夫为 ${this.end - this.start} ms`);            }            render() {                return super.render();            }        };    }    export default withTiming(Home);   

留神:withTiming 是利用 反向继承 实现的一个高阶组件,性能是计算被包裹组件(这里是 Home 组件)的渲染工夫。

  • 页面复用
const withFetching = fetching => WrappedComponent => {    return class extends React.Component {        state = {            data: [],        }        async UNSAFE_componentWillMount() {            const data = await fetching();            this.setState({                data,            });        }        render() {            return <WrappedComponent data={this.state.data} {...this.props} />;        }    }}// pages/page-a.jsexport default withFetching(fetching('science-fiction'))(MovieList);// pages/page-b.jsexport default withFetching(fetching('action'))(MovieList);// pages/page-other.jsexport default withFetching(fetching('some-other-type'))(MovieList);

React组件的state和props有什么区别?

(1)props

props是一个从内部传进组件的参数,次要作为就是从父组件向子组件传递数据,它具备可读性和不变性,只能通过内部组件被动传入新的props来从新渲染子组件,否则子组件的props以及展示模式不会扭转。

(2)state

state的次要作用是用于组件保留、管制以及批改本人的状态,它只能在constructor中初始化,它算是组件的公有属性,不可通过内部拜访和批改,只能通过组件外部的this.setState来批改,批改state属性会导致组件的从新渲染。

(3)区别

  • props 是传递给组件的(相似于函数的形参),而state 是在组件内被组件本人治理的(相似于在一个函数内申明的变量)。
  • props 是不可批改的,所有 React 组件都必须像纯函数一样爱护它们的 props 不被更改。
  • state 是在组件中创立的,个别在 constructor中初始化 state。state 是多变的、能够批改,每次setState都异步更新的。

用户不同权限 能够查看不同的页面 如何实现?

  1. Js形式
    依据用户权限类型,把菜单配置成json, 没有权限的间接不显示
  2. react-router 形式 在route 标签上 增加onEnter事件,进入路由之前替换到首页
<Route path="/home" component={App} onEnter={(nexState,replace)=>{      if(nexState.location.pathname!=='/'){         var  sid = UtilsMoudle.getSidFromUrl(nexState);         if(!sid){            replace("/")         }else{            console.log(sid);         }      }    }}>
  1. 本人封装一个privateRouter组件 外面判断是否有权限,有的话返回
    <Route path={path} component={component} exact={exact}/>
    没有权限的话component 返回一个提示信息的组件。
  2. 扩大一下,如果是依据用权限来判断是否暗藏组件该怎么做呢?
    react 能够应用高阶组件,在高阶组件外面判断是否有权限,而后判断是否返回组件,无权限返回null
    vue 能够应用自定义指令,如果没有权限移除组件
// 须要在入口处增加自定义权限指令v-auth,显示可操作组件Vue.directive('auth', {    bind: function (el, binding, vnode) {        // 用户权限表        const rules = auths        for (let i = 0; i < rules.length; i++) {            const item = rules[i]            if(!binding.value || (binding.value == item.auth)){                // 权限容许则显示组件                return true            }        }        // 移除组件        el.parentNode.removeChild(el)    }})// 应用<template>  <div>    <Button v-auth="admin_user_add">增加用户</Button>    <Button v-auth="admin_user_del">删除用户</Button>    <Button v-auth="admin_user_edit">编辑用户</Button>  </div></template>

什么起因会促使你脱离 create-react-app 的依赖

当你想去配置 webpack 或 babel presets。

对 React Hook 的了解,它的实现原理是什么

React-Hooks 是 React 团队在 React 组件开发实际中,逐步认知到的一个改良点,这背地其实波及对类组件函数组件两种组件模式的思考和偏重。

(1)类组件: 所谓类组件,就是基于 ES6 Class 这种写法,通过继承 React.Component 得来的 React 组件。以下是一个类组件:

class DemoClass extends React.Component {  state = {    text: ""  };  componentDidMount() {    //...  }  changeText = (newText) => {    this.setState({      text: newText    });  };  render() {    return (      <div className="demoClass">        <p>{this.state.text}</p>        <button onClick={this.changeText}>批改</button>      </div>    );  }}

能够看出,React 类组件外部预置了相当多的“现成的货色”等着咱们去调度/定制,state 和生命周期就是这些“现成货色”中的典型。要想得到这些货色,难度也不大,只须要继承一个 React.Component 即可。

当然,这也是类组件的一个不便,它太繁冗了,对于解决许多问题来说,编写一个类组件切实是一个过于简单的姿态。简单的姿态必然带来昂扬的了解老本,这也是咱们所不想看到的。除此之外,因为开发者编写的逻辑在封装后是和组件粘在一起的,这就使得类组件外部的逻辑难以实现拆分和复用。

(2)函数组件:函数组件就是以函数的状态存在的 React 组件。晚期并没有 React-Hooks,函数组件外部无奈定义和保护 state,因而它还有一个别名叫“无状态组件”。以下是一个函数组件:

function DemoFunction(props) {  const { text } = props  return (    <div className="demoFunction">      <p>{`函数组件接管的内容:[${text}]`}</p>    </div>  );}

相比于类组件,函数组件肉眼可见的特质天然包含轻量、灵便、易于组织和保护、较低的学习老本等。

通过比照,从状态上能够对两种组件做辨别,它们之间的区别如下:

  • 类组件须要继承 class,函数组件不须要;
  • 类组件能够拜访生命周期办法,函数组件不能;
  • 类组件中能够获取到实例化后的 this,并基于这个 this 做各种各样的事件,而函数组件不能够;
  • 类组件中能够定义并保护 state(状态),而函数组件不能够;

除此之外,还有一些其余的不同。通过下面的区别,咱们不能说谁好谁坏,它们各有本人的劣势。在 React-Hooks 呈现之前,类组件的能力边界显著强于函数组件。

实际上,类组件和函数组件之间,是面向对象和函数式编程这两套不同的设计思维之间的差别。而函数组件更加符合 React 框架的设计理念: React 组件自身的定位就是函数,一个输出数据、输入 UI 的函数。作为开发者,咱们编写的是申明式的代码,而 React 框架的次要工作,就是及时地把申明式的代码转换为命令式的 DOM 操作,把数据层面的形容映射到用户可见的 UI 变动中去。这就意味着从原则上来讲,React 的数据应该总是紧紧地和渲染绑定在一起的,而类组件做不到这一点。函数组件就真正地将数据和渲染绑定到了一起。函数组件是一个更加匹配其设计理念、也更有利于逻辑拆分与重用的组件表达形式。

为了能让开发者更好的的去编写函数式组件。于是,React-Hooks 便应运而生。

React-Hooks 是一套可能使函数组件更弱小、更灵便的“钩子”。

函数组件比起类组件少了很多货色,比方生命周期、对 state 的治理等。这就给函数组件的应用带来了十分多的局限性,导致咱们并不能应用函数这种模式,写出一个真正的全功能的组件。而React-Hooks 的呈现,就是为了帮忙函数组件补齐这些(绝对于类组件来说)缺失的能力。

如果说函数组件是一台笨重的快艇,那么 React-Hooks 就是一个内容丰盛的零部件箱。“重装战舰”所预置的那些设施,这个箱子里根本全都有,同时它还不强制你全都要,而是容许你自在地抉择和应用你须要的那些能力,而后将这些能力以 Hook(钩子)的模式“钩”进你的组件里,从而定制出一个最适宜你的“专属战舰”。