Reaccionar notas de estudio (dos): React scaffolding, React routing

3. Aplicación React (basada en el andamio React)

1), use create-react-app para crear una aplicación de reacción

1) Reaccionar andamios

react proporciona una biblioteca de andamios para crear proyectos react: create-react-app

La arquitectura técnica general del proyecto es: react + webpack + es6 + eslint

2) Crea el proyecto y empieza

El primer paso, instalación global: npm i -g create-react-app

El segundo paso es cambiar al directorio del proyecto que desea crear y usar el comando: create-react-app hello-react

El tercer paso es ingresar a la carpeta del proyecto: cd hello-react

El cuarto paso es iniciar el proyecto: npm start

3) Reaccionar la estructura del proyecto de andamios

carpeta de recursos pública-estática

Icono de pestaña favicon.icon-website

Index.html —— Página principal

Logo192.png —— imagen del logotipo

Logo512.png —— imagen del logotipo

Archivo de configuración del empaquetador de aplicaciones manifest.json

Archivo de protocolo del rastreador robots.txt

carpeta src-source

Estilo del componente App.css-App

Componente App.js-App

App.test.js: utilizado para probar la aplicación

Index.css-style

Archivo de entrada index.js

Logo.svg —— logo

ReportWebVitals.js: archivo de análisis del rendimiento de la página (requiere compatibilidad con la biblioteca web-vitals)

Archivo de prueba de la unidad setupTests.js-componente (requiere el soporte de la biblioteca jest-dom)

2), puntos de conocimiento relacionados con el caso de todoList

1) Dividir componentes e implementar componentes estáticos. Nota: la escritura de className y style

2) Lista de inicialización dinámica, ¿cómo determinar el estado del componente en el que colocar los datos?

  • Uso de un componente: poner en su propio estado
  • Algunos componentes usan: poner en su estado de componente principal común (oficialmente llamar a esta operación: promoción de estado)

3) Sobre la comunicación entre padre e hijo:

  • [Componente principal] Pasar datos a [componente secundario]: pasar a través de accesorios
  • [Componente secundario] Pasar datos a [componente principal]: pasar a través de accesorios, lo que requiere que el padre le pase una función al niño por adelantado.

Componente padre :

import React, { Component } from 'react'
import Header from './components/Header/index'
import List from './components/List/index'
import Footer from './components/Footer/index'
import './App.css'

//创建并暴露App组件
export default class App extends Component {
    //初始化状态
    state = {
        todos: [
            { id: '001', name: '吃饭', done: true },
            { id: '002', name: '睡觉', done: true },
            { id: '003', name: '打代码', done: false }
        ]
    }

    addTodo = (todoObj) => {
        const { todos } = this.state
        const newTodos = [todoObj, ...todos]
        this.setState({ todos: newTodos })
    }

    updateTodo = (id, done) => {
        const { todos } = this.state
        const newTodos = todos.map(todoObj => {
            if (todoObj.id === id) {
                return { ...todoObj, done: done }
            } else {
                return todoObj
            }
        })
        this.setState({ todos: newTodos })
    }

    deleteTodo = (id) => {
        const { todos } = this.state
        const newTodos = todos.filter((todoObj) => {
            return todoObj.id !== id
        })
        this.setState({ todos: newTodos })
    }

    checkAllTodo = (done) => {
        const { todos } = this.state
        const newTodos = todos.map((todoObj) => {
            return { ...todoObj, done: done }
        })
        this.setState({ todos: newTodos })
    }

    clearAllDone = () => {
        const { todos } = this.state
        const newTodos = todos.filter((todoObj) => {
            return !todoObj.done
        })
        this.setState({ todos: newTodos })
    }

    render() {
        const { todos } = this.state
        return (
            <div className="todo-container">
                <div className="todo-wrap">
                    <Header addTodo={this.addTodo} />
                    <List todos={todos} updateTodo={this.updateTodo} deleteTodo={this.deleteTodo} />
                    <Footer todos={todos} checkAllTodo={this.checkAllTodo} clearAllDone={this.clearAllDone} />
                </div>
            </div>
        );
    }
}

Subcomponente de encabezado :

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { nanoid } from 'nanoid'
import './index.css'

export default class Header extends Component {
    static propTypes = {
        addTodo: PropTypes.func.isRequired
    }

    handleKeyUp = (event) => {
        const { target, keyCode } = event
        const { addTodo } = this.props
        if (keyCode !== 13) {
            return
        }
        if (target.value.trim() === '') {
            alert('输入不能为空')
            return
        }
        const todoObj = { id: nanoid(), name: target.value, done: false }
        addTodo(todoObj)
        target.value = ''
    }

    render() {
        return (
            <div className="todo-header">
                <input onKeyUp={this.handleKeyUp} type="text" placeholder="请输入你的任务名称,按回车键确认" />
            </div>
        )
    }
}

Enumere los subcomponentes :

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Item from '../Item/index'
import './index.css'

export default class List extends Component {
    static propTypes = {
        todos: PropTypes.array.isRequired,
        updateTodo: PropTypes.func.isRequired,
        deleteTodo: PropTypes.func.isRequired
    }

    render() {
        const { todos, updateTodo, deleteTodo } = this.props

        return (
            <ul className="todo-main">
                {
                    todos.map(todo => {
                        return <Item key={todo.id} {...todo} updateTodo={updateTodo} deleteTodo={deleteTodo} />
                    })
                }
            </ul>
        )
    }
}

Subcomponente de artículo :

import React, { Component } from 'react'
import './index.css'

export default class Item extends Component {
    state = {
        mouse: false
    }

    handleMouse = (flag) => {
        return () => {
            this.setState({ mouse: flag })
        }
    }

    handleCheck = (id) => {
        const { updateTodo } = this.props
        return (event) => {
            updateTodo(id, event.target.checked)
        }
    }

    handleDelete = (id) => {
        const { deleteTodo } = this.props
        if (window.confirm('确定删除吗?')) {
            deleteTodo(id)
        }
    }

    render() {
        const { id, name, done } = this.props
        const { mouse } = this.state

        return (
            <li style={
   
   { backgroundColor: mouse ? '#ddd' : 'white' }} onMouseLeave={this.handleMouse(false)} onMouseEnter={this.handleMouse(true)}>
                <label>
                    <input type="checkbox" checked={done} onChange={this.handleCheck(id)} />
                    <span>{name}</span>
                </label>
                <button onClick={() => this.handleDelete(id)} className="btn btn-danger" style={
   
   { display: mouse ? 'block' : 'none' }}>删除</button>
            </li>
        )
    }
}

Subcomponentes de pie de página :

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import './index.css'

export default class Footer extends Component {
    static propTypes = {
        todos: PropTypes.array.isRequired,
        checkAllTodo: PropTypes.func.isRequired,
        clearAllDone: PropTypes.func.isRequired
    }

    handleCheckAll = (event) => {
        const { checkAllTodo } = this.props
        checkAllTodo(event.target.checked)
    }

    handleClearAllDone = () => {
        const { clearAllDone } = this.props
        clearAllDone()
    }

    render() {
        const { todos } = this.props
        const doneCount = todos.reduce((pre, todo) => { return pre + (todo.done ? 1 : 0) }, 0)
        const total = todos.length

        return (
            <div className="todo-footer">
                <label>
                    <input type="checkbox" onChange={this.handleCheckAll} checked={total !== 0 && doneCount === total} />
                </label>
                <span>
                    <span>已完成{doneCount}</span> / 全部{total}
                </span>
                <button onClick={this.handleClearAllDone} className="btn btn-danger">清除已完成任务</button>
            </div>
        )
    }
}

4) Preste atención a la diferencia entre defaultChecked y check, hay similitudes: defaultValue y value

5) ¿Dónde está el estado, dónde está el método de funcionamiento del estado?

4. Reaccionar enrutamiento

1), comprensión relevante

1) Comprensión de SPA
  • Aplicación web de una sola página (aplicación web de una sola página, SPA)
  • Toda la aplicación tiene una sola página completa.
  • Hacer clic en el enlace de la página no actualizará la página, solo una actualización parcial de la página.
  • Todos los datos deben obtenerse a través de solicitudes ajax y mostrarse de forma asincrónica en la interfaz
2) Comprensión del enrutamiento

¿Qué es el enrutamiento ?

  • Una ruta es una relación de mapeo (clave: valor)
  • la clave es la ruta, el valor puede ser función o componente

Clasificación de ruta :

a. Enrutamiento de back-end :

Comprensión: el valor es una función que se utiliza para procesar la solicitud enviada por el cliente.

Ruta de registro:router.get(path, function(req, res))

Proceso de trabajo: cuando el nodo recibe una solicitud, encuentra una ruta coincidente de acuerdo con la ruta de la solicitud, llama a la función en la ruta para procesar la solicitud y devuelve los datos de respuesta.

b. Enrutamiento de front-end :

Enrutamiento del lado del navegador, el valor es un componente, se usa para mostrar el contenido de la página

Ruta de registro:<Route path="/test" component={Test}>

Proceso de trabajo: cuando la ruta del navegador se convierte en / prueba, el componente de enrutamiento actual se convertirá en el componente de prueba

2), el uso de enrutamiento básico

1) Introducir react-router-dom

hilo añadir react-router-dom

2) Uso básico de enrutamiento
  1. Aclare el área de navegación y el área de visualización en la interfaz
  2. La etiqueta a en el área de navegación se cambia a la etiqueta Enlace<Link to="/xxxxx">Demo</Link>
  3. Escriba etiquetas de ruta en el área de visualización para que coincidan con las rutas<Route path='/xxxx' component={Demo}/>
  4. <App>Envuelve uno <BrowserRouter>o<HashRouter>
3) Implementación del código

App.jsx :

import React, { Component } from 'react'
import { Link, Route } from 'react-router-dom'
import Home from './pages/Home/index'
import About from './pages/About/index'

export default class App extends Component {
    render() {
        return (
            <div>
                <div className="row">
                    <div className="col-xs-offset-2 col-xs-8">
                        <div className="page-header"><h2>React Router Demo</h2></div>
                    </div>
                </div>

                <div className="row">
                    <div className="col-xs-2 col-xs-offset-2">
                        <div className="list-group">
                            {/* 编写路由链接 */}
                            <Link className="list-group-item" to="/about">About</Link>
                            <Link className="list-group-item" to="/home">Home</Link>
                        </div>
                    </div>
                    <div className="col-xs-6">
                        <div className="panel">
                            <div className="panel-body">
                                {/* 注册路由 */}
                                <Route path="/home" component={Home} />
                                <Route path="/about" component={About} />
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}

index.js :

import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import App from './App'

ReactDOM.render(
    <BrowserRouter><App /></BrowserRouter>,
    document.getElementById('root')
)

3), componentes de enrutamiento y componentes generales

1) Escritura diferente

Componentes generales:<Demo/>

Componentes de enrutamiento:<Route path="/demo" component={Demo}/>

2) Diferentes ubicaciones de almacenamiento

Componentes generales: componentes

Componente de enrutamiento: páginas

Los accesorios recibidos son diferentes:

Componentes generales: qué se pasa al escribir la etiqueta del componente, qué se puede recibir

Componente de enrutamiento: recibió tres atributos fijos

history:
	go: ƒ go(n)
	goBack: ƒ goBack()
	goForward: ƒ goForward()
	push: ƒ push(path, state)
	replace: ƒ replace(path, state)
location:
	pathname: "/about"
	search: ""
	state: undefined
match:
	params: {}
	path: "/about"
	url: "/about"

4) NavLink y paquete NavLink

  1. NavLink puede realizar el resaltado de los enlaces de enrutamiento y especificar el nombre del estilo a través de activeClassName
  2. El contenido del cuerpo de la etiqueta es un atributo de etiqueta especial
  3. A través de this.props.children, puede obtener el contenido del cuerpo de la etiqueta
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { NavLink } from 'react-router-dom'
import './index.css'

export default class MyNavLink extends Component {
    static propTypes = {
        to: PropTypes.string.isRequired,
        children: PropTypes.string.isRequired
    }

    render() {
        return (
            <NavLink activeClassName="demo" className="list-group-item" {...this.props} />
        )
    }
}

App.jsx :

import React, { Component } from 'react'
import { Route } from 'react-router-dom'
import MyNavLink from './components/MyNavLink/index'
import Home from './pages/Home/index'
import About from './pages/About/index'

export default class App extends Component {
    render() {
        return (
            <div>
                <div className="row">
                    <div className="col-xs-offset-2 col-xs-8">
                        <div className="page-header"><h2>React Router Demo</h2></div>
                    </div>
                </div>

                <div className="row">
                    <div className="col-xs-2 col-xs-offset-2">
                        <div className="list-group">
                            {/* 编写路由链接 */}
                            <MyNavLink to="/home">Home</MyNavLink>
                            <MyNavLink to="/about">About</MyNavLink>
                        </div>
                    </div>
                    <div className="col-xs-6">
                        <div className="panel">
                            <div className="panel-body">
                                {/* 注册路由 */}
                                <Route path="/home" component={Home} />
                                <Route path="/about" component={About} />
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}

5) Uso de Switch

  1. En circunstancias normales, la ruta y el componente tienen una correspondencia uno a uno
  2. El conmutador puede mejorar la eficiencia de coincidencia de enrutamiento (coincidencia única)

App.jsx :

import React, { Component } from 'react'
import { Route, Switch } from 'react-router-dom'
import MyNavLink from './components/MyNavLink/index'
import Home from './pages/Home/index'
import About from './pages/About/index'

export default class App extends Component {
    render() {
        return (
            <div>
                <div className="row">
                    <div className="col-xs-offset-2 col-xs-8">
                        <div className="page-header"><h2>React Router Demo</h2></div>
                    </div>
                </div>

                <div className="row">
                    <div className="col-xs-2 col-xs-offset-2">
                        <div className="list-group">
                            {/* 编写路由链接 */}
                            <MyNavLink to="/home">Home</MyNavLink>
                            <MyNavLink to="/about">About</MyNavLink>
                        </div>
                    </div>
                    <div className="col-xs-6">
                        <div className="panel">
                            <div className="panel-body">
                                {/* 注册路由 */}
                                <Switch>
                                    <Route path="/home" component={Home} />
                                    <Route path="/about" component={About} />
                                </Switch>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}

6) Coincidencia estricta y coincidencia aproximada de enrutamiento

  1. La coincidencia aproximada se utiliza de forma predeterminada (simplemente recuerde: [ruta de entrada] debe incluir [ruta coincidente] y el orden debe ser el mismo)
  2. Active la coincidencia estricta:<Route exact={true} path="/about" component={About}/>
  3. La concordancia estricta no debe activarse de forma casual. Es necesario volver a activarla. A veces, si se activa, no podrá seguir haciendo coincidir rutas secundarias.

7) El uso de Redirect

Por lo general, está escrito al final de todos los registros de enrutamiento. Cuando no todas las rutas pueden coincidir, salte a la ruta especificada por Redirect.

<Switch>
	<Route path="/home" component={Home} />
	<Route path="/about" component={About} />
	<Redirect to="/about" />
</Switch>

8), enrutamiento anidado

  1. Al registrar una ruta secundaria, escriba el valor de la ruta de la ruta principal
  2. La coincidencia de rutas se realiza en el orden de rutas registradas.

9), pase los parámetros al componente de enrutamiento

1) parámetros de params

Enlace de enrutamiento (transporte de parámetros):

<Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>

Ruta registrada (declaración recibida):

<Route path="/home/message/detail/:id/:title" component={Detail} />

Recibir parámetros:this.props.match.params

Componente padre :

import React, { Component } from 'react'
import { Link, Route } from 'react-router-dom'
import Detail from './Detail/index'

export default class Message extends Component {
    state = {
        messageArr: [
            { id: '01', title: '消息1' },
            { id: '02', title: '消息2' },
            { id: '03', title: '消息3' }
        ]
    }
    render() {
        const { messageArr } = this.state
        return (
            <div>
                <ul>
                    {
                        messageArr.map((msgObj) => {
                            return (
                                <li key={msgObj.id}>
                                    {/* 向路由组件传递params参数 */}
                                    <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>&nbsp;&nbsp;
                                </li>
                            )
                        })
                    }
                </ul>
                <hr />
                {/* 声明接收params参数 */}
                <Route path="/home/message/detail/:id/:title" component={Detail} />
            </div>
        )
    }
}

Subcomponente :

import React, { Component } from 'react'

const detailData = [
    { id: '01', content: '消息1详情' },
    { id: '02', content: '消息2详情' },
    { id: '03', content: '消息3详情' }
]
export default class Detail extends Component {
    render() {
        //接收params参数
        const { id, title } = this.props.match.params
        const findResult = detailData.find((detailObj) => {
            return detailObj.id === id
        })

        return (
            <ul>
                <li>ID:{id}</li>
                <li>TITLE:{title}</li>
                <li>CONTENT:{findResult.content}</li>
            </ul>
        )
    }
}
2) parámetro de búsqueda

Enlace de enrutamiento (transporte de parámetros):

<Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>

Registro de enrutamiento (no es necesario declarar, el registro normal es suficiente):

<Route path="/home/message/detail/" component={Detail} />

Recibir parámetros:this.props.location.search

Nota: La búsqueda obtenida es una cadena codificada en urlencoded, que debe analizarse con querystring

Componente padre :

import React, { Component } from 'react'
import { Link, Route } from 'react-router-dom'
import Detail from './Detail/index'

export default class Message extends Component {
    state = {
        messageArr: [
            { id: '01', title: '消息1' },
            { id: '02', title: '消息2' },
            { id: '03', title: '消息3' }
        ]
    }
    render() {
        const { messageArr } = this.state
        return (
            <div>
                <ul>
                    {
                        messageArr.map((msgObj) => {
                            return (
                                <li key={msgObj.id}>
                                    {/* 向路由组件传递search参数 */}
                                    <Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>&nbsp;&nbsp;
                                </li>
                            )
                        })
                    }
                </ul>
                <hr />
                {/* search参数无需声明接收,正常注册路由即可 */}
                <Route path="/home/message/detail/" component={Detail} />
            </div>
        )
    }
}

Subcomponente :

import React, { Component } from 'react'
import qs from 'querystring'

const detailData = [
    { id: '01', content: '消息1详情' },
    { id: '02', content: '消息2详情' },
    { id: '03', content: '消息3详情' }
]
export default class Detail extends Component {
    render() {
        //接收search参数
        const { search } = this.props.location
        const { id, title } = qs.parse(search.slice(1))
        const findResult = detailData.find((detailObj) => {
            return detailObj.id === id
        })

        return (
            <ul>
                <li>ID:{id}</li>
                <li>TITLE:{title}</li>
                <li>CONTENT:{findResult.content}</li>
            </ul>
        )
    }
}
3) parámetro de estado

Enlace de enrutamiento (transporte de parámetros):

<Link to={
   
   { pathname: '/home/message/detail/', state: { id: msgObj.id, title: msgObj.title } }}>{msgObj.title}</Link>

Registro de enrutamiento (no es necesario declarar, el registro normal es suficiente):

<Route path="/home/message/detail/" component={Detail} />

Recibir parámetros:this.props.location.state

Nota: Refresh también puede retener los parámetros

Componente padre :

import React, { Component } from 'react'
import { Link, Route } from 'react-router-dom'
import Detail from './Detail/index'

export default class Message extends Component {
    state = {
        messageArr: [
            { id: '01', title: '消息1' },
            { id: '02', title: '消息2' },
            { id: '03', title: '消息3' }
        ]
    }
    render() {
        const { messageArr } = this.state
        return (
            <div>
                <ul>
                    {
                        messageArr.map((msgObj) => {
                            return (
                                <li key={msgObj.id}>
                                    {/* 向路由组件传递state参数 */}
                                    <Link to={
   
   { pathname: '/home/message/detail/', state: { id: msgObj.id, title: msgObj.title } }}>{msgObj.title}</Link>&nbsp;&nbsp;
                                </li>
                            )
                        })
                    }
                </ul>
                <hr />
                {/* state参数无需声明接收,正常注册路由即可 */}
                <Route path="/home/message/detail/" component={Detail} />
            </div>
        )
    }
}

Subcomponente :

import React, { Component } from 'react'

const detailData = [
    { id: '01', content: '消息1详情' },
    { id: '02', content: '消息2详情' },
    { id: '03', content: '消息3详情' }
]
export default class Detail extends Component {
    render() {
        //接收state参数
        const { id, title } = this.props.location.state || {}
        const findResult = detailData.find((detailObj) => {
            return detailObj.id === id
        }) || {}

        return (
            <ul>
                <li>ID:{id}</li>
                <li>TITLE:{title}</li>
                <li>CONTENT:{findResult.content}</li>
            </ul>
        )
    }
}

10) Enrutamiento y navegación programáticos

Utilice this.prosp.historyla API en el objeto para saltar, avanzar y volver a la ruta de operación.

  • this.prosp.history.push()
  • this.prosp.history.replace()
  • this.prosp.history.goBack()
  • this.prosp.history.goForward()
  • this.prosp.history.go()

11), la diferencia entre BrowserRouter y HashRouter

  1. Los principios subyacentes son diferentes

    BrowserRouter usa la API de historial H5, que no es compatible con IE9 y versiones anteriores

    HashRouter usa el valor hash de la URL

  2. La expresión de la ruta es diferente

    No hay un # en la ruta de BrowserRouter, por ejemplo: localhost: 3000 / demo / test

    La ruta de HashRouter contiene #, por ejemplo: localhost: 3000 / # / demo / test

  3. Impacto en los parámetros de estado de enrutamiento después de la actualización

    BrowserRouter no tiene ningún efecto, porque el estado se almacena en el objeto de historial

    Después de que se actualice el HashRouter, se perderán los parámetros de estado de enrutamiento

  4. Nota: HashRouter se puede utilizar para resolver algunos problemas relacionados con errores de ruta

Información de video :

https://www.bilibili.com/video/BV1wy4y1D7JT

Dirección de origen :

https://github.com/hxt970311/react_demo

Supongo que te gusta

Origin blog.csdn.net/qq_40378034/article/details/113813680
Recomendado
Clasificación