React认知–hooks和hooks轮播图案例

这是我参与更文挑战的第15天,活动详情查看: 更文挑战

一、hooks介绍和应用场景

hooks是16.8之后出现的新特性,React团队希望,组件不要变成复杂的容器,最好只是数据流的管道。开发者根据需要,组合管道即可。组件最佳的写法是函数,而不是类。React早就支持函数组件,下面就是一个例子。

 function Welcome(props) {
        return <h1> Hello ,{props.name}</h1>
    }
复制代码

但是这种写法有重大的限制,必须是纯函数,不能包含状态,也不支持生命周期方法,因此无法取代类。

React Hooks设计的目的,就是加强版的函数组件,完全不使用类,就能写出一个全功能的组件。

Hooks可以让无状态组件实现有状态组件的部分功能,比如设置state,使用钩子函数:
componentDidMount、componentDidUpdate、componentWillUnmount。

二、hooks中的useState

从useState中解构出属性和set属性方法

import React,{useState, useEffect} from 'react'

export default function Hooks() {
    const [title,setTile] = useState('首页')

    function changeTitle() {
        setTile('改变title')
    }
}
复制代码

三、hooks中的useEffect方法

useEffect可以获取改变了的属性

 // 更新数据的回调处理 第一个参数cb方法 第二个参数需要使用的参数(优化, 不传也可以获取到) useEffect如果值相同就不会再执行了
    useEffect(() => {
            return () => {
                // return中的cb方法相当于componentWillUnmount
                document.title = title
                console.log('componentWillUnmount...')
            }
        },
        [title]
    )
复制代码

例子

import React,{useState,useEffect} from 'react';
import Css from "./assets/css/app.css";

//  使用无状态组件
function App() {
    const [title, setTitle] = useState('首页') // useState 解构属性和设置属性的方法

    function changeTitle() {
        setTitle('hooks')
    }



    // 更新数据的回调处理 第一个参数cb方法 第二个参数需要使用的参数(优化, 不传也可以获取到) useEffect如果值相同就不会再执行了
    useEffect(() => {
            return () => {
                // return中的cb方法相当于componentWillUnmount
                document.title = title
                console.log('componentWillUnmount...')
            }
        },
        [title]
    )

    return (
        <div className={Css['app']}>
            <div>{title}</div>
            <button onClick={changeTitle.bind(this)}>改变title</button>
        </div>
    )
}

export default App;

复制代码

效果

2021-06-16-20-58-29.gif

四、useReducer

React本身不提供状态管理功能, 通常需要使用外部库. 这方面最常用的库是Redux。

Redux的核心概念是, 组件发出action与状态管理器通信。状态管理器收到action以后,使用Reducer函数算出新的状态,Reducer函数的形式是(state,action)=》 newState

例子:
新建一个处理useReducer方法的js

export let defaultState = {count: 0}

export let countReducer = (state =defaultState,action) =>
                         {
                             switch (action.type) {
                                 case 'inc': // 增加
                                     state = {...state, ...action.payload}
                                     break;
                                 case 'dec': // 减少
                                    state = {...state, ...action.payload}
                                 break;
                             }
                             return state
                         }
复制代码

然后在app.js中使用useReducer

import React,{useReducer} from 'react';
import Css from "./assets/css/app.css";
import {defaultState,countReducer} from './hooksReducer/reducerCount'
let iCount = 0
function App() {
    let thing = useReducer(countReducer,defaultState)
    let [state,dispatch] = thing
    return (
        <div className={Css['app']}>
                计算:
                <button onClick={()=> dispatch({type: 'dec', payload: {count: --iCount}})}>-</button>
                    {state.count}
                <button onClick={()=> dispatch({type: 'inc', payload: {count: ++iCount}})}>+</button>
        </div>
    )
}

export default App;

复制代码

效果

2021-06-16-22-14-51.gif

五. useContext

相当于Vue中的bus在组件中通信

5.1 新建一个context.js文件

import React from 'react'

export default React.createContext()
复制代码

5.2 封装count组件

这里相当于消费者

import React,{useContext} from 'react';
import Context from '../../context'
function Count() {
    let countContext = useContext(Context)
    return (
        <div>
            子组件计算:
            <button onClick={()=> countContext.dispatch({type: 'dec', payload: {count: --countContext.state.count}})}>-</button>
            {countContext.state.count}
            <button onClick={()=> countContext.dispatch({type: 'inc', payload: {count: ++countContext.state.count}})}>+</button>
        </div>
    )
}

export default Count;

复制代码

5.3 在app.js中使用context.js

这里相当于信息提供者

import React,{useReducer} from 'react';
import Css from "./assets/css/app.css";
import {defaultState,countReducer} from './hooksReducer/reducerCount'
import Context from './context'
import  Count from './component/count'
let iCount = 0
function App() {
    let thing = useReducer(countReducer,defaultState)
    let [state,dispatch] = thing
    return (
        <div className={Css['app']}>
            <Context.Provider value={{state,dispatch}}>
                <Count></Count>
                计算:
                <button onClick={()=> dispatch({type: 'dec', payload: {count: --iCount}})}>-</button>
                    {state.count}
                <button onClick={()=> dispatch({type: 'inc', payload: {count: ++iCount}})}>+</button>
            </Context.Provider>
        </div>
    )
}

export default App;

复制代码

效果

2021-06-16-22-24-04.gif

六、hooks轮播图案例

6.1 app.js中

import React from 'react';
import Swiper from './components/swiper';
import Css from "./assets/css/app.css";
class App extends React.Component{
    constructor(){
        super();
        this.state={
            images:[],
            images2:[]
        };
    }
    componentDidMount(){
        setTimeout(()=>{
            let images=[
                {src:require("./assets/images/banner1.jpg"),url:"https://pages.tmall.com/wow/a/act/tmall/tmc/23759/wupr?spm=875.7931836/B.2016006.d6.66144265aPX4zF&trackInfo=20160815100101;64866506034;287638;587431337429;3;287638_587431337429;1007.14152.68669.100200300000000;92ba02ea-a2a8-4bbe-99ac-d5c3abf2eba5;3;0;10000002&item_id=587431337429&pvid=92ba02ea-a2a8-4bbe-99ac-d5c3abf2eba5&pos=3&activity_id=287638&wh_pid=industry-170400&acm=07055.1003.1.2519102&scm=1003.1.20160815.OTHER_0_6801489"},
                {src:require("./assets/images/banner2.jpg"),url:"https://pages.tmall.com/wow/a/act/tmall/tmc/23759/wupr?spm=875.7931836/B.2016006.d1.66144265aPX4zF&trackInfo=20160815100101;64950842484;288994;530549532317;3;288994_530549532317;1007.14152.68669.100200300000000;92ba02ea-a2a8-4bbe-99ac-d5c3abf2eba5;1;0;10000002&item_id=530549532317&pvid=92ba02ea-a2a8-4bbe-99ac-d5c3abf2eba5&pos=1&activity_id=288994&wh_pid=industry-170636&acm=07055.1003.1.2519102&scm=1003.1.20160815.OTHER_0_6810849"},
                {src:require("./assets/images/banner3.jpg"),url:"https://www.tmall.com/wow/brand/act/fashion?acm=lb-zebra-2386-265936.1003.4.410386&scm=1003.4.lb-zebra-2386-265936.OTHER_1_410386&ali_trackid=19_4803ba43894904cab9c8c08820f2e4a5&spm=875.7931836/B.2016006.d2"}
            ];
            this.setState({images:images});
            let images2=[
                {src:require("./assets/images/banner2.jpg"),url:"https://pages.tmall.com/wow/a/act/tmall/tmc/23759/wupr?spm=875.7931836/B.2016006.d6.66144265aPX4zF&trackInfo=20160815100101;64866506034;287638;587431337429;3;287638_587431337429;1007.14152.68669.100200300000000;92ba02ea-a2a8-4bbe-99ac-d5c3abf2eba5;3;0;10000002&item_id=587431337429&pvid=92ba02ea-a2a8-4bbe-99ac-d5c3abf2eba5&pos=3&activity_id=287638&wh_pid=industry-170400&acm=07055.1003.1.2519102&scm=1003.1.20160815.OTHER_0_6801489"},
                {src:require("./assets/images/banner3.jpg"),url:"https://pages.tmall.com/wow/a/act/tmall/tmc/23759/wupr?spm=875.7931836/B.2016006.d1.66144265aPX4zF&trackInfo=20160815100101;64950842484;288994;530549532317;3;288994_530549532317;1007.14152.68669.100200300000000;92ba02ea-a2a8-4bbe-99ac-d5c3abf2eba5;1;0;10000002&item_id=530549532317&pvid=92ba02ea-a2a8-4bbe-99ac-d5c3abf2eba5&pos=1&activity_id=288994&wh_pid=industry-170636&acm=07055.1003.1.2519102&scm=1003.1.20160815.OTHER_0_6810849"},
                {src:require("./assets/images/banner1.jpg"),url:"https://www.tmall.com/wow/brand/act/fashion?acm=lb-zebra-2386-265936.1003.4.410386&scm=1003.4.lb-zebra-2386-265936.OTHER_1_410386&ali_trackid=19_4803ba43894904cab9c8c08820f2e4a5&spm=875.7931836/B.2016006.d2"}
            ];
            this.setState({images2:images2})
        },400)
    }
    render(){
        return (
            <div className={Css["app"]}>
                <div class={Css["banner"]}>
                    <Swiper data={this.state.images}></Swiper>
                </div>
                <div className={Css["banner"]}>
                    <Swiper data={this.state.images2}></Swiper>
                </div>
            </div>
        )
    }
}

export default App;

复制代码

6.2 封装的swiper hooks组件

index.js

import React from 'react';
import Hoc from './hoc';
import "./style.css";
export default Hoc((props)=>{
    return(
        <div className="my-swiper-main" onMouseOver={props.stop} onMouseOut={props.autoPlay}>
            {
                (props.data && props.data.length>0) && props.data.map((item,index)=>{
                    return (
                        <div className={item.active?"slide show":"slide"} key={index}>
                            <a href={item.url} target="_blank" rel="noopener noreferrer"><img src={item.src} alt=""/></a>
                        </div>
                    )
                })
            }
            <div className="pagination">
                {
                    (props.data && props.data.length>0) && props.data.map((item,index)=>{
                        return (
                            <div className={item.active?"dot active":"dot"} key={index} onClick={()=>{props.changeImg(index)}}></div>
                        )
                    })
                }
            </div>
        </div>
    )
})
复制代码

6.3 hoc.js

import React,{useEffect,useState,useRef,useCallback} from 'react';
import PropTypes from 'prop-types';
export default function Hoc(WithComponent){
    function HocComponent(props){
        let [data,setData]=useState([]);
        let [isInit,setIsInit]=useState(true);
        let [iIndex,setIndex]=useState(0);
        //创建一个表示,通用的容器
        let timer=useRef(null);
        //点击切换图片
        function changeImg(index){
            setIndex(index);
            if(data && data.length>0){
                for(let i=0;i<data.length;i++){
                    if(data[i].active){
                        data[i].active=false;
                        break;
                    }
                }
                data[index].active=true;
                setData(data);
            }
        }
        //自动播放
        const autoPlay=useCallback(()=>{
            clearInterval(timer.current);
            timer.current=setInterval(()=>{
                let tmpIndex=iIndex;
                if(data && data.length>0){
                    for(let i=0;i<data.length;i++){
                        if(data[i].active){
                            data[i].active=false;
                            break;
                        }
                    }
                    if(tmpIndex>=data.length-1){
                        tmpIndex=0;
                    }else {
                        tmpIndex++;
                    }
                    data[tmpIndex].active=true;
                    setIndex(tmpIndex);
                    setData(data);
                }
            },3000)
        },[data,iIndex]);
        //停止自动播放
        function stop(){
            clearInterval(timer.current);
        }
        useEffect(()=>{
            if(props.data && props.data.length>0 && isInit){
                setIsInit(false);
                for(let i=0;i<props.data.length;i++){
                    if(i===0){
                        props.data[i].active=true;
                    }else{
                        props.data[i].active=false;
                    }
                }
                setData(props.data);
            }
            autoPlay();
            //页面离开时执行
            return ()=>{
                clearInterval(timer.current);
            }
        },[props.data,isInit,autoPlay]);
        let newsProps={
            changeImg,
            data,
            stop,
            autoPlay
        };
        return (
            <WithComponent {...props} {...newsProps}></WithComponent>
        )
    }
    HocComponent.propTypes={
        data:PropTypes.array.isRequired
    };
    return HocComponent;
}
复制代码

效果

2021-06-17-07-58-51.gif

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享