美文网首页
react的新特性(二)---hooks

react的新特性(二)---hooks

作者: Mr无愧于心 | 来源:发表于2019-06-14 09:54 被阅读0次

    产生背景

    • Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
    • react hooks 要解决的问题是状态共享,(自定义hook)是继render-propsHOC组件之后的第三种状态共享方案,不会产生jsx嵌套地狱的问题。
    • Hook 使你在无需修改组件结构的情况下复用状态逻辑。

    状态共享的方式

    1. render-props方式
      render prop就是给组件添加一个值为函数的属性,这个函数可以在组件渲染(fn)的时候调用
    class Mouse extends React.Component{
      constructor(props){
        super(props);
        this.state = { x: 0, y: 0 };
      }
      handleMouseMove=(event)=>{
        this.setState({
          x: event.clientX,
          y: event.clientY
        });
      }
      render() {
        return (
          <div onMouseMove={this.handleMouseMove}>
            <p>The current mouse position is ({this.state.x}, {this.state.y})</p>
            {this.props.fn(this.state)} // 这个比较关键 fn 就是这个函数的属性
          </div>
        );
      }
    }
    //另一个组件cat,需要拿到mouse的数据
    class Cat extends React.Component {
      render() {
        const mouse = this.props.mouse;
        return (
          <img 
             src="/cat.jpg" 
             style={{ position: 'absolute', left: mouse.x, top: mouse.y }} />
        );
      }
    }
    //组合这两个组件
    class MouseTracker extends React.Component {
      render() {
        return (
          <div>
            <h1>Move the mouse around!</h1>
            <Mouse fn={mouse => (//将Mouse组件中的this.state拿到传递给cat组件
              <Cat mouse={mouse} />
            )}/>
          </div>
        );
      }
    }
    //相当于cat组件使用了mouse组件,以后再有的dog,pig组件都可以使用mouse组件(实现mouse的重用);
    
    1. HOC组件(高阶组件是参数为组件,返回值为新组件的函数)
    //每个经过高阶组件处理过的组件都会复用高阶组件里边的所有逻辑,
    //但原则是高阶组件是一个纯函数,不会修改传入的组件
    function high(Component){
      return class extends React.Component{
        constructor(){
          this.state={
            open:false
          }
        }
        componentDidMount(){
          console.log('haha')
        }
        change=()=>{
          this.setState((state)=>{//用到state需要使用回调函数修改state的值
              return {open:!state.open}
          })
        }
        render(){
          return <Component  open={this.state.open}  change={this.change}>
                 </Component>
        }
      }
    }
    
    class ToggleButton extends Component{//不带有自身的状态能够实现组件的复用
      constructor(props){
        super(props)
      }
      render(){
        let {open,change}=this.props;
        return <Fragment>
                  <button type="primary" onClick={change}> 
                    toggle Modal
                  </button>
                  <div>{open}</div> //拿到open值
              </Fragment>
      }
    }
    const EnhancedComponent = high(ToggleButton);
    

    内置hooks

    • useState

    像是 function 形式的 setState,其实这等价于依赖注入,与使用 setState 相比,这个组件是没有状态的。

    当不使用hooks时,需要使用class创建组件,使用state作为内部私有状态

    class ToggleBotton extends React.Component{
      constructor(props){
        super(props);
        this.state={open:false}
      }
      toggle=()=>{
        this.setState((state)=>{
          return {open:!state.open}
        })
      }
      render(){
        <Fragment>
          <button type="primary" onClick={this.toggle}> 
            toggle Modal
          </button>
          <div>{this.state.open}</div> //拿到open值
        </Fragment>
      }
    }
    

    使用hooks的useState

    function ToggleBotton() {
      const [open, setOpen] = useState(false);
      //useState接收一个默认值(可以是任何数据类型),
      //返回数组有一对值,不带set的用来取值,带set的用来修改值,可以取任何名字
      const toggle=()=>{
        setOpen(!open)//直接使用setOpen修改open值,不用使用setState
      }
      return (
        <Fragment>
          <button type="primary" onClick={toggle}> 
            toggle Modal
          </button>
          <div>{open}</div> //直接用 open取值,不用使用this.state.open
        </Fragment>
      );
    }
    

    useState在一个组件内可以多次调用,也可以将参数设置为对象数据类型,减少调用

    const [instete, setInstete] = useState({aa:1,bb:2,cc:3...});
    
    • useEffect

    1. 可以把 useEffect Hook 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。
    2. 接收一个回调函数做参数
    3. 本要在componentWillUnmount中要编写的逻辑,放在 useEffect执行的回调函数中 返回的一个新函数中。。。
    4. 一个组件中可以调用多个useEffect,不同的逻辑放在各自的useEffect中,使逻辑更加清晰,当组件初始或重新渲染时会依次执行所有的useEffect
    5. 可以通过跳过 Effect 进行性能优化
    useEffect(() => {
      console.log('useEffect 的代码既会在初始化时候执行,也会在后续每次重新渲染时执行')
      const subscription = props.source.subscribe();
      return () => {//返回的函数用来清除计时器,解绑事件啥的,防止内存泄漏
        //相当于componentWillUnmount要编写的逻辑,如果没有这些需求也可以不写
        subscription.unsubscribe();
      };
    });
    

    以上代码等价于

    componentDidMount(){
      console.log('useEffect 的代码既会在初始化时候执行,也会在后续每次重新渲染时执行')
      const subscription = props.source.subscribe();
    }
    componentDidUpdate(){
      console.log('useEffect 的代码既会在初始化时候执行,也会在后续每次重新渲染时执行')
      const subscription = props.source.subscribe();
    }
    componentWillUnmount{
      subscription.unsubscribe();
    }
    

    effect的性能优化(useEffect的第二个参数)

    //第二个参数是一个数组,说明当数组里边的数据发生变化的时候才会触发调用useEffect的回调
    useEffect(() => {
      document.title = `You clicked ${count} times`;
    }, [count]); // 仅在 count 更改时才更新,避免多余的调用
    

    如果只想在初始化的时候实现依次调用的化,第二个参数写成空数组 [ ] 即可

    自定义hooks(解决状态共享)

    1. hooks的规则
    • 不要在循环,条件或嵌套函数中调用 Hook
    • 不要在普通的 JavaScript 函数中调用 Hook
      ✅ 在 React 的函数组件中调用 Hook
      ✅ 在自定义 Hook 中调用其他 Hook
    • Hook 函数必须以 "use" 命名开头
    2.自定义hooks的使用
    • 自定义 Hook 是一个函数,其名称必须以 “use” 开头,函数内部可以调用其他的 Hook。
    • 函数式组件都可以使用这个自定义的hook
    • 在两个组件中使用相同的 Hook 不会共享 state,不同组件之间的state没有关系,所以也不能实现数据的持久化
    • 你可以创建涵盖各种场景的自定义 Hook,如表单处理、动画、订阅声明、计时器。。。
    import React, { useState, useEffect } from 'react';
    
    //定义自定义hook
    function useFriendStatus(friendID) {
      const [isOnline, setIsOnline] = useState(null);
      useEffect(() => {
        function handleStatusChange(status) {
          setIsOnline(status.isOnline);
        }
        ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
        return () => {
          ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
        };
      });
      return isOnline;
    }
    
    
    //使用自定义hook
    function FriendListItem(props) {
      const isOnline = useFriendStatus(props.friend.id);
      return (
        <li style={{ color: isOnline ? 'green' : 'black' }}>
          {props.friend.name}
        </li>
      );
    }
    

    hooks的特点

    • 多个状态不会产生嵌套,写法还是平铺的(renderProps 可以通过 compose 解决,可不但使用略为繁琐,而且因为强制封装一个新对象而增加了实体数量)。
    • Hooks 可以引用其他 Hooks。
    • 更容易将组件的 UI 与状态分离。

    最后的目标是----有状态的组件没有渲染,有渲染的组件没有状态

    状态和ui分离,便于逻辑的复用

    相关文章

      网友评论

          本文标题:react的新特性(二)---hooks

          本文链接:https://www.haomeiwen.com/subject/sxqsfctx.html