React16 新特性总结

createPortal

createPortal 的出现为 弹窗、对话框 等脱离文档流的组件开发提供了便利,Portals 提供了一种很好的将子节点渲染到父组件以外的 DOM 节点的方式。

const modalRoot = document.body;

class Modal extends React.Component {
    constructor(props) {
        super(props);
        this.el = document.createElement('div');
    }

    componentDidMount() {
        modalRoot.appendChild(this.el);
    }

    componentWillUnmount() {
        modalRoot.removeChild(this.el);
    }

    render() {
        return ReactDOM.createPortal(
            this.props.children,
            this.el,
        );
    }
} 

render方法新增返回类型

render方法支持直接返回string,number,boolean,null,portal,以及fragments(带有key属性的数组),这可以在一定程度上减少页面的DOM层级

// 不需要再将元素作为子元素装载到根元素下面
render() {
  return [
        <div>一步 01</div>,
        <div>一步 02</div>,
        <div>一步 03</div>,
        <div>一步 04</div>
    ];
} 

新的组件生命周期钩子

static getDerivedStateFromProps(nextProps, prevState)

static静态方法,在es5中这么实现:

function Person() {}
Person.getCount = function () {} 

以上就是static静态方法的原理。由于“this”只能获取属性是根据原型链,而静态方法不在原型链上,所以,在组件实例内无通过this调用static方法,static方法也无法根据"this"调用实例的其他方法。

静态方法和动态方法区别


static getDerivedStateFromProps(nextProps, prevState) {
    const {type} = nextProps;
    // 当传入的type发生变化的时候,更新state
    if (type !== prevState.type) {
        return {
            type,
        };
    }
    // 否则,对于state不进行任何操作
    return null;
} 

// 你可能会用以下这样做,虽然这样做看起来也没问题,用上面的方法更加安全,不会对this做误操作
componentWillReceiveProps (nextProps) {
    if (this.state.name !== nextProps.name) {
        this.setState({
            name: nextProps.name
        });
    }
}

componentDidCatch(error, info)

如果错误在组件的渲染或者生命周期方法中被抛出,则会触发该函数。

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  componentDidCatch(error, info) {
    this.setState({ hasError: true });
  }

  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
} 

然后在顶部或任何地方,你可以这样使用它

<ErrorBoundary>
  <MyWidget />
</ErrorBoundary>

性能方面

lazy / Suspense

React.lazy() 提供了动态 import 组件的能力,实现代码分割。

Suspense 作用是在等待组件时 suspend(暂停)渲染,并显示加载标识。

import React, {lazy, Suspense} from 'react';
const OtherComponent = lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <OtherComponent />
    </Suspense>
  );
} 

React.Fragments

如果不喜欢写数组呢,可以使用这个(简写<></>),这样并不会在DOM中增加额外节点,相当于 render 返回数组元素。

	return (
        <React.Fragment>    
            <div>一步 01</div>
            <div>一步 02</div>
            <div>一步 03</div>
            <div>一步 04</div>
        </React.Fragment>
    ); 

ref

React16中有两种创建Ref的方法

constructor () {
    this.inputNameRef = React.createRef();
    this.switchRef = React.createRef();
}

render () {
    // 通过this.inputNameRef.current 可以获取到input实例
    return (
        <div>
             <input ref={this.inputNameRef} />
             <Switch ref={this.switchRef} />
        </div>
    )
} 
render () {
    // 通过回调ref的方式实现
    // 通过this.inputNameRef 可以获取到input实例
    // this.switchRef可以获取Switch的实例
    return (
        <div>
             <input ref={(ref) => this.inputNameRef = ref} />
             <Switch ref={(ref) => this.switchRef = ref} />
        </div>
    )
} 

hooks

useState

// 传入初始值,作为 state
const [state, setState] = useState(initialState)

//  `惰性初始 state`;传入函数,由函数计算出的值作为 state
// 此函数只在初始渲染时被调用
const [state, setState] = useState(() => {
  const initialState = someExpensiveComputation(props)
  return initialState
}) 

useEffect

  • Effect Hook 可以让你在函数组件中执行副作用操作,数据获取,设置订阅以及手动更改 React 组件中的 DOM 都属于副作用。
  • React 会等待浏览器完成画面渲染之后才会延迟调用 useEffect,传递给 useEffect 的函数在每次渲染中都会有所不同,我们可以在 effect 中获取最新的 count 的值,而不用担心其过期
  • 每个 effect 都可以返回一个清除函数, React 会在组件卸载的时候执行清除操作, useEffect 默认就会在调用一个新的 effect 之前对前一个 effect 进行清理
  • 如果某些特定值在两次重渲染之间没有发生变化,你可以通知 React 跳过对 effect 的调用,只要传递数组作为 useEffect 的第二个可选参数即可,如果你要使用此优化方式,请确保数组中包含了所有外部作用域中会随时间变化并且在 effect 中使用的变量,否则你的代码会引用到先前渲染中的旧变量
  • 如果想执行只运行一次的 effect(仅在组件挂载和卸载时执行),可以传递一个空数组([])

以下就是一个创建订阅的例子:

useEffect(() => {
  const subscription = props.source.subscribe()
  return () => {
    // 清除订阅
    subscription.unsubscribe()
  }
}, [依赖]) 

规则

不要在循环,条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层调用他们。

(*推荐启用 eslint-plugin-react-hooks 的 ESLint 插件)

useMemo和useCallback

useCallback和useMemo的参数跟useEffect一致,他们之间最大的区别有是useEffect会用于处理副作用,而前两个hooks不能。

useMemo和useCallback都会在组件第一次渲染的时候执行,之后会在其依赖的变量发生改变时再次执行;并且这两个hooks都返回缓存的值,useMemo返回缓存的变量,useCallback返回缓存的函数。

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
); 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值