Destructuring 解构赋值

props是一个对象,可以通过解构赋值减少代码的重复书写

  1. props = {
  2. name: 'Arto Hellas',
  3. age: 35,
  4. }

在组件内解构

  1. const Hello = (props) => {
  2. const { name, age } = props

在参数内解构

  1. //import React from 'react'
  2. const Hello = ({ name, age, ...props }) => {
  3. console.log(props.gender)
  4. const bornYear = () => new Date().getFullYear() - age
  5. return (
  6. <>
  7. <p>Hello {name}, you are {age} years old</p>
  8. <p>So you were probably born in {bornYear()}</p>
  9. </>
  10. )
  11. }
  12. const App = () => {
  13. const name = 'Peter'
  14. const age = 10
  15. return (
  16. <>
  17. <h1>Greetings</h1>
  18. <Hello name="Maya" age={26 + 10} gender='female' />
  19. <Hello name={name} age={age} />
  20. </>
  21. )
  22. }

Page re-rendering 页面重渲染

在App.js里显示一个数值,让它递增,当counter变化时,react不会自动刷新页面,需要手动刷新

  1. const App = (props) => {
  2. const { counter } = props
  3. return (
  4. <div>{counter}</div>
  5. )
  6. }
  1. let counter = 1
  2. const refresh = () => {
  3. ReactDOM.render(
  4. <App counter={counter} />,
  5. document.getElementById('root')
  6. );
  7. }
  8. setInterval(() => {
  9. refresh() // 调用render手动刷新
  10. counter += 1
  11. }, 1000)

重复调用 ReactDOM.render-方法并不是重新渲染组件的推荐方法。 接下来,我们将介绍一种更好的,实现相同效果的方法。

Stateful component 有状态组件

我们通过 React 的 state hook 向应用的App 组件中添加状态。
每次 setCounter 修改状态时,它都会导致组件重新渲染

  1. import React, { useState } from 'react'
  2. const App = (props) => {
  3. const [counter, setCounter] = useState(0)
  4. setTimeout(
  5. () => setCounter(counter + 1),
  6. 1000
  7. )
  8. return (
  9. <div>{counter}</div>
  10. )
  11. }

Event handling 事件处理

让点击按钮时counter加1

  1. import React, { useState } from "react"
  2. const App = () => {
  3. const [counter, setCounter] = useState(0)
  4. const handleClick = () => {
  5. setCounter(counter + 1)
  6. }
  7. return (
  8. <div>
  9. <div>{counter}</div>
  10. <button onClick={handleClick}>plus</button>
  11. </div>
  12. )
  13. }

事件处理函数也可以在 onClick 属性的值中直接定义:

  1. <button onClick={() => setCounter(counter + 1)}>plus</button>

事件处理程序应该是一个函数 或一个函数引用
如果把onClick属性改成下面这样变成一个函数调用,当页面第一次渲染时,会调用setCounter(counter + 1),setCounter会导致页面再次渲染,形成死循环,最后页面崩溃

  1. <button onClick={setCounter(counter + 1)}>plus</button>

通常在 JSX-模板 中定义事件处理程序并不是一个好的实践。
但这里没问题,因为我们的事件处理程序非常简单。
但无论如何,让我们将事件处理程序分离成单独的函数:

  1. const App = () => {
  2. const [counter, setCounter] = useState(0)
  3. const increaseByOne = () => setCounter(counter + 1)
  4. const setToZero = () => setCounter(0)
  5. return (
  6. <div>
  7. <div>{counter}</div>
  8. <button onClick={increaseByOne}>
  9. plus
  10. </button>
  11. <button onClick={setToZero}>
  12. zero
  13. </button>
  14. </div>
  15. )
  16. }

Passing state to child components 将状态传递给子组件

在 React 中的一个最佳实践是将 状态提升 ,提升到组件层次结构中足够高的位置,文档中是这么说的:

Often, several components need to reflect the same changing data. We recommend lifting the shared state up to their closest common ancestor. 通常,几个组件需要反映相同的变化数据。 我们建议将共享状态提升到它们最接近的共同祖先。

让我们将counter和button拆分成组件,并将状态通过props传给这些子组件

  1. const Display = (props) => {
  2. return (
  3. <div>{props.counter}</div>
  4. )
  5. }
  6. const Button = (props) => {
  7. return (
  8. <button onClick={props.handleClick}>
  9. {props.text}
  10. </button>
  11. )
  12. }
  13. const App = () => {
  14. const [counter, setCounter] = useState(0)
  15. const increaseByOne = () => setCounter(counter + 1)
  16. const decreaseByOne = () => setCounter(counter - 1)
  17. const setToZero = () => setCounter(0)
  18. return (
  19. <div>
  20. <Display counter={counter} />
  21. <Button text={'plus'} handleClick={increaseByOne} />
  22. <Button text={'Zero'} handleClick={setToZero} />
  23. <Button text={'minus'} handleClick={decreaseByOne} />
  24. </div>
  25. )
  26. }

调用一个改变状态的函数会导致组件的重新渲染。
每次渲染,子组件的props就能获取到counter的最新值

Refactoring the components 重构组件

使用解构赋值箭头函数特性重构子组件

  1. const Display = ({ counter }) => <div>{counter}</div>
  2. const Button = ({ handleClick, text }) => (
  3. <button onClick={handleClick}>
  4. {text}
  5. </button>
  6. )