React入门

165 阅读3分钟

Context

Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。(有点全局变量的感觉)

//数据提供者
const BatteryContext = createContext();
const OnlineContext = createContext();

class Leaf extends Component{
  render() {
    return (
        <BatteryContext.Consumer>
            {
              battery => (
                  <OnlineContext.Consumer>
                      {
                          online => <h1>battery: {battery} online: {String(online)}</h1>
                      }
                  </OnlineContext.Consumer>
              )
            }
        </BatteryContext.Consumer>
    );
  }
}

class Middle extends Component {
  render(){
    return <Leaf/>
  }
}

class App extends Component{
  state={
    battery: 60,
    online: false
  };
  render() {
    const {battery, online} = this.state;
    return (
        <BatteryContext.Provider value={battery}>
          <OnlineContext.Provider value={online}>
            <button type="button" onClick={()=>{this.setState({battery: battery-1})}}>Press</button>
            <button type="button" onClick={()=>{this.setState({online: !online})}}>Switch</button>
            <Middle></Middle>
          </OnlineContext.Provider>
        </BatteryContext.Provider>
    );
  }
}

contextType

一般一个组件只有一个Context,这个时候可以用contextType来简化代码。官方文档的例子:

class ThemedButton extends React.Component {
  // 指定 contextType 读取当前的 theme context。
  // React 会往上找到最近的 theme Provider,然后使用它的值。
  // 在这个例子中,当前的 theme 值为 “dark”。
  static contextType = ThemeContext;
  render() {
    return <Button theme={this.context} />;
  }
}

React.lazy Suspense Error Boundaries

React.lazy 动态加载组件的方式
Suspense 动态加载组件空隙显示的组件
Error Boundaries 错误边界,如果动态加载组件失败显示的组件

PureComponent memo (优化性能的范畴)

PureComponent 和 Component 的区别在于其他组件的setState会不会触发本身的重新render;PureComponent实现 shouldComponentUpdate();以浅层对比 prop 和 state 的方式来实现了该函数。
memo 作用跟 PureComponent 一样,不同的是 PureComponent 用于class组件;memo 用于函数组件,而不适用 class 组件。

useEffect

  • 副作用是指绑定事件、网络请求、访问DOM元素这些
  • 通常在Mount之后、Update之后、Unmount之前 进行
  • 分别对应 componentDidMount componentDidUpdate
useEffect(()=>{
    
    return ()=>{
        //回调函数
    }
},[])

useEffect第一次调用相当于 componentDidMount,以后的每次执行相当于componentDidUpdate,回调函数会清除上一次effect,相当于 componentWillUnmount

怎么控制 useEffect 多次渲染都会执行呢?第二个参数传递空数组 [] , 可以让 useEffect 只执行一次。

Hooks中使用Context

使用useContext,在函数组件中不能使用contextType了,static只能用在class中。

const CountContext = createContext();

const Counter = ()=>{
    const count = useContext(CountContext)
    return (
        <h1>{count}</h1>
    )
}

const App = (props)=>{
    const [count, setCount] = useState(0);
    return(
        <div>
            <button type="button" onClick={()=>{setCount(count+1)}}>add</button>
            <CountContext.Provider value={count}>
                <Counter/>
            </CountContext.Provider>
        </div>
    )
}

Hooks中memo useMemo

memo的使用可以避免组件本身props没有变化而重新渲染的问题;useMemo 中的函数可以在指定的情况下才执行,同时useMemo可以返回函数,这个时候可以用useCallBack

const Counter = React.memo((props)=>{
    console.log("Counter render");
    return (
        <h1 onClick={props.onClick}>{props.count}</h1>
    )
});

const App = (props)=>{
    const [count, setCount] = useState(0);

    const double = useMemo(()=>{
        return count * 2;
    }, [count===3]);

    // const onClick = useMemo(()=>{
    //     return ()=>{
    //         console.log('clicked')
    //     }
    // },[])
    //等价useMemo
    const onClick = useCallback(()=>{
        console.log('clicked')
    },[])

    return(
        <div>
            <button type="button" onClick={()=>{setCount(count+1)}}>add</button>
            <Counter count={double} onClick={onClick}/>
        </div>
    )
}

Hooks中Ref useRef

  • 获取子组件或者DOM节点的句柄,useRef不能用在函数组件中
class Counter extends PureComponent{
    speak(){
        console.log(`current count is ${this.props.count}`)
    }
    render() {
        const {props} = this;
        console.log("Counter render");
        return (
            <h1 onClick={props.onClick}>{props.count}</h1>
        )
    }
}

const App = (props)=>{
    const [count, setCount] = useState(0);

    const double = useMemo(()=>{
        return count * 2;
    }, [count===3]);

    // const onClick = useMemo(()=>{
    //     return ()=>{
    //         console.log('clicked')
    //     }
    // },[])
    const counterRef = useRef();

    const onClick = useCallback(()=>{
        console.log('clicked');
        console.log(counterRef.current)
        counterRef.current.speak();
    },[counterRef])



    return(
        <div>
            <button type="button" onClick={()=>{setCount(count+1)}}>add</button>
            <Counter ref={counterRef} count={double} onClick={onClick}/>
        </div>
    )
}
  • 渲染周期之间共享数据的存储
    const it = useRef();
    useEffect(()=>{
        it.current = setInterval(()=>{
            setCount(count=>count+1)
        }, 1000)
    }, [])

    useEffect(()=>{
        if(count>=10){
            clearInterval(it.current)
        }
    });