520 Al ver que la diosa está tan caliente, escribí un acondicionador de aire de verano sin deshabilitar React

Participo en el "Concurso creativo de principios de verano" para obtener más información, consulte: Concurso creativo de principios de verano

Resumen

Cuando llegó el 520 y coincidió con la temporada de verano, estuve enamorado de la diosa durante muchos días y decidí invitarla a ver una película esta noche. Cuando pensé en el dulce momento de la noche, simplemente tomé mi teléfono móvil y Envié un mensaje a la diosa directamente, y mis amigos estaban esperando.Come comida para perros, sé lleno.

imagen.png

Dado que la diosa es tan sexy, ¿cómo puedo reconciliarme como un mensajero de reacción? No, tengo que escribir un acondicionador de aire para la diosa, tal vez pueda salir al mundo de dos personas esta noche. Es realmente difícil escribir un acondicionador de aire de verano, no porque el código sea engorroso, pero este acondicionador de aire de verano debe sumergirse en cuatro partes de la brisa primaveral, tres partes de la luz de la luna, dos partes de un poco borracho y uno parte de sus cejas. No hablemos mucho, número uno.

imagen.png

Crear proyecto

> create-react-app air-condition
复制代码

División de componentes

Ya sea escribiendo React o Vue, el punto más importante siempre es cómo determinar la división del trabajo entre los componentes. Los componentes son la idea de dividir y conquistar. ¡Es como una llanta de refacción, donde necesita ser movida! Debido a que este acondicionador de aire de verano React no es complicado, incluso un poco simple, por lo que no entraré en detalles sobre las partes html y css. Veamos directamente cómo dividir los componentes. Como se muestra en la figura a continuación, el componente de la aplicación es el componente raíz, que envuelve los componentes Panel, CopyWriting, Button y Audio. El componente Panel también contiene el componente Temp. Indicaremos (la temperatura actual del acondicionador de aire), el comportamiento (botón de ajuste, reproducción de sonido y pausa) todo Póngalo en el componente de la aplicación, porque los componentes Panel, Botón y Audio necesitan compartir datos, y la forma más conveniente es, sin duda, almacenar los datos compartidos en su componente principal común, que React llama a la promoción estatal .

imagen.png

División de componentes

índice

import React from 'react'
import ReactDOM from 'react-dom/client'

import App from './App'

const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
)
复制代码

aplicación

import { useState, useRef, useCallback } from 'react'

import Panel from './component/Panel'
import CopyWriting from './component/CopyWriting'
import Button from './component/Button'
import Audio from './component/Audio'

const App = () => {
  // 使用useRef得到Audio组件的实例
  const ref = useRef()
  // temp为存储的空调温度,默认为26
  const [temp, setTemp] = useState(26)
  // 调高温度
  const up = useCallback(() => {
    const result = temp + 1
    ref.current.playTip()
    // 温度最高为31
    if (result > 31) { return false }
    setTemp(result)
  }, [temp])
  // 调低温度
  const down = useCallback(() => {
    const result = temp - 1
    ref.current.playTip()
    // 温度最低为16
    if (result < 16) { return false }
    setTemp(result)
  }, [temp])
  // 开关按钮
  const toSwitch = useCallback(() => {
    ref.current.playTip()
    ref.current.playRun()
  }, [temp])

  return (
    <>
      <section className="title">
        <h1 style={{ fontWeight: 400 }}>夏日空调</h1>
      </section>
      <section className="panel">
        <Panel temp={temp} />
      </section>
      <section className="copywriting">
        <CopyWriting />
      </section>
      <section className="button">
        <Button up={up} down={down} toSwitch={toSwitch} />
      </section>
      <section style={{ display: 'none' }}>
        <Audio ref={ref} />
      </section>
    </>
  )
}

export default App
复制代码

En el componente App, usamos useRef para obtener el método en el subcomponente Audio. Los métodos up, down, toSwitch se pasan al componente Button a través de props Para causar una representación innecesaria del componente Button, usamos useCallback para envolver el método pasado, y el componente Button en sí mismo se envuelve con React.memo.

Panel

import Temp from '../Temp'

// 生成div
const productDiv = length => Array.from({ length }).map((_, i) => <div key={i}></div>)

const Panel = ({ temp }) => {
    return (
        <div className="air-condition">
            <div className="a-tag">
                <div className="a-t-header">
                    {productDiv(6)}
                </div>
                <div className="a-t-content-1">
                    <div className="c-l">
                        <div className="c-l-1"></div>
                        <div className="c-l-2"></div>
                        <div className="c-l-3"></div>
                    </div>
                    <div className="c-r">
                        <p className="c-r-grade"></p>
                    </div>
                </div>
                <div className="a-t-content-2">
                    <div className="c-2-title">
                        {productDiv(9)}
                    </div>
                    <div className="c-2">
                        <div className="c-2-1">
                            {productDiv(6)}
                        </div>
                        <div className="c-2-2">
                            {productDiv(6)}
                        </div>
                    </div>
                </div>
                <div className="a-t-footer">
                    {productDiv(6)}
                </div>
            </div>
            <div className="a-screen">
                <div className="s-icon">
                    <img src={snowflake} className="img-100" alt="" />
                </div>
                <div className="s-temp">
                    <Temp temp={temp} />
                </div>
            </div>
            <div className="a-line"></div>
            <div className="a-wind">
                <img src={wind} alt="failed" className="img-l" />
                <img src={wind} alt="failed" className="img-c" />
                <img src={wind} alt="failed" className="img-r" />
            </div>
        </div>
    )
}

export default Panel
复制代码

我们也可以选择不使用Temp组件,而是将温度直接显示在Panel组件中,这种方式同样可以实现效果,但是为了数据和页面更好的分离,我们的Panel组件只负责接收数据,Temp组件只负责显示数据,这样如果后期需要对Panel组件添加一些复杂交互、功能,我们只需要对Panel组件进行修改,如果需要对空调温度的显示界面进行修改时,我们只需要修改Temp组件即可。

Temp

import React from 'react'

const Temp = ({ temp }) => {
    return (
        <>
            <span>{temp}</span>
            <span className="s-t-symbol"></span>
            <span>c</span>
        </>
    )
}

export default React.memo(Temp)
复制代码

Temp组件只是用来展示UI,不进行其它任何操作,无论Temp组件后期修改后多么花里胡哨,温度(temp)我们已经拿到了,无论怎么修改均不影响其它功能。同样,为了引起Temp组件的不必要渲染,我们依然使用React.memo对组件自身进行包裹。

CopyWriting

import { useState, useEffect } from "react"

// 获取文案
const getContent = async () => {
    try {
        const connect = await fetch('https://v1.hitokoto.cn?c=d')
        const data = await connect.json()
        return data
    } catch (e) { return false }
}

const CopyWriting = () => {
    // 存储获取到的文案
    const [text, setText] = useState({ hitokoto: '', quote: '' })
    useEffect(() => {
        const update = async () => {
            const data = await getContent()
            const from_who = data.from_who ? data.from_who : ''
            data.quote = `——${from_who}${data.from}》`
            setText(data)
        }
        const token = setInterval(update, 6000)
        update()
        // 组件卸载时清除定时器
        return () => clearInterval(token)
    }, [])
    return (
        <>
            <p>{text.hitokoto}</p>
            <p>{text.quote}</p>
        </>
    )
}

export default CopyWriting
复制代码

因为本项目相对较小,无需其它复杂功能,所以getContent采用fetch获取文案,如果非要使用xhr、axios倒显得有些冗余了。我们此处将获取到的文案存放在了useState中,还有一种方式,此处并未采用。即使用useRef来存储数据,当获取到数据后,使用useState刷新页面。例如

const Comp = () => {
    const ref = useRef(1)
    const [force, setForce] = useState()
    const handle = () => {
        const result = ref.current
        ref.current = result + 1
        setForce(result)
    }
    return (
        <>
            <span>{ref.current}</span>
            <button onClick={handle}>自增</button>
        </>
    )
}
复制代码

Button

import React, { useState } from 'react'

const Button = ({ up, down, toSwitch }) => {
    // 存储开关按钮的背景颜色
    const [bg, setBg] = useState({ open: '#f33531', off: '#43a047', flag: false })
    // 播放声音、切换状态
    const switchState = () => {
        toSwitch()
        setBg({ ...bg, flag: !bg.flag })
    }
    return (
        <>
            <div className="b-inc" onClick={() => up()}>
                <img src={upArrow} className="img-5" alt="failed" />
            </div>
            <div
                className="b-switch"
                onClick={() => switchState()}
                style={{ backgroundColor: bg.flag ? bg.open : bg.off }}
            >
                <img src={switchBtns} className="img-5" alt="failed" />
            </div>
            <div className="b-dec" onClick={() => down()}>
                <img src={downArrow} className="img-5" alt="failed" />
            </div>
        </>
    )
}

export default React.memo(Button)
复制代码

Button组件自身使用React.memo进行包裹,一般情况下,React.memo与useCallback、useMemo搭配使用,使用useCallback、useMemo的原因是无论父组件如何操作,始终保证传递给Button组件的props不变,使用React.memo是为了对props做比较,这样才不会引起Button组件的重新渲染。React.memo类似于类式组件的PureComponent。

Audio

import React, { useRef, useImperativeHandle } from 'react'

const Audio = (_, ref) => {
    const tipRef = useRef()
    const runRef1 = useRef()
    // 要传递给父组件的方法
    useImperativeHandle(ref, () => ({
        playTip: () => {
            tipRef.current.play()
        },
        playRun: () => {
            const flag = runRef1.current.paused
            if (flag) return setTimeout(() => runRef1.current.play(), 300);
            runRef1.current.pause()
        },
    }))
    return (
        <>
            <audio src={tip} ref={tipRef} ></audio>
            <audio src={run} ref={runRef1} loop></audio>
        </>
    )
}

// 使用React.forwardRef将子组件ref转发给父组件
export default React.forwardRef(Audio)
复制代码

Audio组件中,我们使用React.forwardRef与useImperativeHandle让父组件可以操作子组件。注意,类式组件并不需要这么做,只需要在使用子组件时直接ref即可,显然,hooks并不支持这种写法。

// son
class Son extends React.Component {
  constructor() {
    super()
    this.state = { value: 1 }
    this.inc = () => this.setState({ value: this.state.value + 1 })
  }
  render() {
    const { value } = this.state
    const { inc } = this
    return (
      <>
        <span>{value}</span>
        <button onClick={inc}>加1</button>
      </>
    )
  }
}
// father
// father可以是函数式组件也可以是类式组件
class Father extends React.Component {
  constructor() {
    super()
    this.ref = React.createRef()
    this.inc = () => this.ref.current.inc()
  }
  render() {
    const { ref, inc } = this
    return (
      <>
        <Son ref={ref} />
        <button onClick={inc}>加21</button>
      </>
    )
  }
}
复制代码

项目完成

> npm start
复制代码

imagen.png

在线演示地址

1.在线演示

2.码上掘金

El proyecto se ha completado aquí. Además, me gustaría recomendarle la columna de una pregunta de JavsScript de una pregunta al día de JS que escribí todos los días durante 2-3 minutos. Creo que la tecnología definitivamente mejorará. . Nos vemos chicos, se lo voy a mostrar a la diosa.

imagen.png

Pensé para mis adentros, la diosa debe estar tan feliz, qué película debería ver esta noche, escuché que hay "Can You Don't Leave Me" y "Secret Love: Orange Born in Huainan" en el horario 520. Creo que ella me acompañará todos los días.Todas son películas irrepetibles.

imagen.png

¿Por qué la diosa es así? ¿Mi aire acondicionado no es lo suficientemente bueno? Después de pensarlo, tal vez Tutu se fue a dormir y no quería ser molestado.

Supongo que te gusta

Origin juejin.im/post/7100478900673150989
Recomendado
Clasificación