一文帶你瞭解React中的函數組件

1. 創建方式

 //  寫法一
const Hello = (props) => {      
    return <div>{props.message}</div>
}

 //  寫法二
const Hello = props => <div>{props.message}</div>  

// 寫法三
function Hello(props) {
    return <div>{props.message}</div>
}

2. 函數組件代替類組件

面臨的問題

  • 函數組件沒有state => React v16.8.0推出Hooks API,其中的一個API叫做useState可以解決問題
  • 函數組件沒有生命周期 => React v16.8.0推出Hooks API,其中的一個API叫做useEffect可以解決問題

我們對比一下兩種組件實現 n + 1 的例子

類組件

class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            n: 0
        }
    }

    addNum = () => {
        this.setState({n: this.state.n + 1})
    }

    render() {
        return (
            <div className='App'>
                <span>n:{this.state.n}</span>
                <button onClick={this.addNum}>n+1</button>
            </div>
        )
    }
}

函數組件

const App = props => {
    const [n,setN] = React.useState(0)
    function addNum(){
        setN(n + 1)
    }
    return (
        <div className='App'>
            {n}
            <button onClick={addNum}>+1</button>
        </div>
    )
}

相比之下函數組件更為簡潔一些

使用 useEffect 解決生命周期問題

1.模擬 componentDidMount 首次渲染

useEffect(() => {     //  模擬componentDidMount  首次渲染
        console.log('use effect')
    },[])    // 空數組必須寫

2.模擬 componentDidUpdate

const [n, setN] = React.useState(0)
useEffect(() => {     //  模擬  componentDidUpdate 
        console.log('n 變化瞭')
    },[n])  // 數組裡面可以寫多個參數表示監聽多個變量

useEffect(() => {     //  模擬  componentDidUpdate 
        console.log('任意屬性變更瞭')
    })  // 不寫數組表示監聽所有 useState  的變量
//  但是這樣在第一次渲染時也會觸發函數的執行  
 解決方法使用自定義Hook 見下一標題

3.模擬componentWillUnmount

  useEffect(() => {    
        return () => {
            console.log('Child 銷毀瞭')
        }
    })    //  返回一個函數 在銷毀時執行

4.constructor

函數組件執行的時候,就相當於constructor

5.shouldComponentUpdate

後面的 React.memo和useMemo可以解決

6.render

函數組件的返回值就是render的返回值.

//  模擬render裡面寫邏輯
const X = (props) => {
    console.log('我是要寫的邏輯')
    return (
        <div>邏輯模擬</div>
    )
}

const App = props => {
    let [childVisible, setChildVisible] = useState(true)

    const changeVisible = () => {
        setChildVisible(!childVisible)
    }

    return (
        <div className='App'>
            {childVisible ? <button onClick={changeVisible}>{childVisible}</button> :
                <button onClick={changeVisible}>hide</button>}
            {/*{childVisible ? <Child/> : null}*/}
            <Child/>
            <X/>     
        </div>
    )
}   // 一個函數便是一個組件

3. 自定義 Hook 之 useUpdate

解決上面 n 值初次渲染就執行的問題

const App = props => {
    const [n, setN] = useState(0)
    const onClick = () => {
        setN(n + 1)
    }
    const [nUpdateCount, setNUpdateCount] = useState(0)
    useEffect(() => {    // 初次渲染就執行 + 1
        setNUpdateCount(nUpdateCount + 1)
    }, [n])
    useEffect(() => {    // 初次渲染就執行 判斷是否大於1 
        if(nUpdateCount > 1){
            console.log('n變瞭')
        }
    },[nUpdateCount])
    return (
        <div className='App'>
            n值變成瞭:{n}
            <button onClick={onClick}>n+1</button>
        </div>
    )
}
//  通過使用兩次 useEffect 第一個觸發第二個 useEffect 函數計數,大於0便是n值變化瞭

上面的代碼很亂 改進一下

const useX = (fn, dep) => {   // 這就是自定義 Hook 這就可以抽離成別的文件
    const [count, setCount] = useState(0)
    useEffect(() => {
        setCount(x => x + 1)
    }, [dep])
    useEffect(() => {
        if (count > 1) {
            fn()
        }
    }, [count,fn])
}

const App = props => {
    const [n, setN] = useState(0)
    const onClick = () => {
        setN(n + 1)
    }
    useX(() => {
        console.log('n 變化瞭')
    }, n)
    return (
        <div className='App'>
            n值變成瞭:{n}
            <button onClick={onClick}>n+1</button>
        </div>
    )
}

補充:函數組件代替 class 組件

為什麼要用函數組件代替 class 組件?別問,簡單!相比類組件來說,函數組件確實要簡單太多, 不妨看一個 +1 的例子:

class App extends React.Component {
	const App = props = > {
		constructor() {
			const[n, setN] = React.useState(0);
			super();
			const addN = () = > {
				this.state = {
					setN(n + 1);
					n: 0
				}
			};
			return (
			} < div > {
				n
			}
			addN = () = > { < button onClick = {
					addN
				} > +1 < /button></div >
					this.setState({
						n: this.state.n + 1
					});)
		};
	}
	render() {
		return ( < div className = "App" > {
			this.state.n
		} < button onClick = {
			this.addN
		} > +1 < /button>
      </div > ); //這是公共的渲染部分
	}
	const rootElement = document.getElementById("root");
}
ReactDOM.render( < App / > , rootElement);

通過上面的例子你可以看出,同樣是實現 +1 的操作,類組件要比函數組件復雜的多,類組件不僅涉及到 extends、setState 等 API,還會涉及到 this 的使用,而且代碼量還很多。反觀函數組件就要清爽的多,所以在開發中推薦使用函數組件。

總結

到此這篇關於React中函數組件的文章就介紹到這瞭,更多相關React函數組件內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: