React system study notes -- super basic -- super detailed -- super concise -- React application based on scaffolding (3)

1 Create a react project using creat-react-app

Scaffolding is built with webpack, we don't have to build it from scratch now

Xxx scaffolding: used to help the program to quickly create a template project based on the xxx library

  • Contains all required configurations (syntax check, jsx compilation, devServer...)
  • Downloaded all related dependencies
  • A simple effect can be run directly

React provides a scaffolding library for creating react projects: create-react-app (a project based on React scaffolding, read each file of the project, and then add your own business logic)

The overall technical architecture of the project is: react+webpack+es6+eslint

Features of projects developed using scaffolding: modularization, componentization, and engineering

With this library create-react-app, scaffolding can be created

1.1 Create a project and start it

The old version of the steps to create a project

Global installation:npm i -g create-react-app

Switch to the directory where you want to create the project and use the command:create-react-arr hello-react

Go to the project folder:cd hello-react

Startup project:npm start

Now steps to create project

npx create-react-app my-app
cd my-app
npm start

1.2 react scaffolding project structure

public ---- static resource folder

​ favicon.icon ------ website tab icon

​index.html -------- main page

​ logo192.png ------- logo image

​ logo512.png ------- logo image

​ manifest.json ----- Application packer configuration file

​ robots.txt -------- crawler protocol file

insert image description here

src ---- source code folder

​ App.css -------- App component style

​App.js --------- App component

​ App.test.js ---- used to test the App

​ index.css ------ styles

​index.js ------- entry file (equivalent to main.js)

​ logo.svg ------- logo image

​ reportWebVitals.js

​ — page performance analysis file (requires the support of web-vitals library)

​ setupTests.js

​ ---- Component unit test file (requires jest-dom library support)

<!-- React.StrictMode帮我们检查App组件及其子组件里面的写法是否合理 -->
<React.StrictMode>
  <App />
</React.StrictMode>

insert image description here

1.3 Hello component experience

a detail

第一种情况:
//文件module.js中定义
const React = {
    
    a:1, b:2}
React.Component = class Component {
    
    }
export default React
//使用
import React from './module.js'
const {
    
    Component} = React//这叫从React身上解构
第二种情况:
const React = {
    
    a:1, b:2}
export class Component {
    
    }//使用分别暴露,暴露Component
export default React//使用默认暴露,暴露React
//使用
import React,{
    
    Component} from './module.js'
//注意这不叫解构!!!这就是分别暴露之后的与引入,说明module文件里面使用了多种暴露形式

Distinguish between component and normal function files

The first type: when all js ends, look at the first letter, and the first letter of the component is capitalized

The second way: write the suffix of the component file as .jsx, there are two kinds of suffixes that can be omitted when importing files in react: js and jsx

Optimization point: when importing files, the path name is too long, you can define index.jsx under the folder, so that you can omit the file name when importing, and write less
insert image description here

Entry file index.js

//React18不推荐这样写,会有警告,新写法可以参考React18
//引入react核心库
import React from "react";
//引入ReactDOM
import ReactDOM from "react-dom";
import App from './App'

//渲染App组件到页面
ReactDOM.render(<App />, document.getElementById('root'))

insert image description here

One note: Because subcomponents are eventually introduced and used in the App component, if subcomponent style naming conflicts will occur, it is sometimes necessary to do style modularization (less can be avoided by nesting relationships)
insert image description here

2 React plugin in VScode

ES7+ React/Redux/React-Native snippets 作者:dsznajder

3. Component coding process of functional interface

Split components: split interface, extract components

Realize static components: use components to achieve static page effects

Implement dynamic components

​ Dynamically display initialization data

​ data type

​ Data name

​ Which component is saved in?

​ Interaction (starting from binding event listening)

4 TodoList case

Split static components and styles

App.jsx puts subcomponents, App.css puts public styles, and the rest of the components take away

About where todos data is placed

At present, we have only learned how to pass data props from father to son, so the data is temporarily placed in the common father App

parent to child data transfer

//App给List组件传
<List todos={
    
    this.state.todos} />

//List组件给Item组件传
//接收、解构
const {
    
     todos } = this.props
//传递的两种写法
//return <Item key={todo.id} id={todo.id} name={todo.name} done={todo.done} />
return <Item key={
    
    todo.id} {
    
    ...todo} />

//Item组件同样接收、解构、展示即可

Added todo: The input in the Header should cause the state change in the App component (transfer from the child to the parent)

The App component passes a function to the Header subcomponent. The function callback is written in the App, and the data in the subcomponent can be returned to the parent component App in the form of parameters.

App.jsx

//用于添加一个todo,接收一个todo对象
addTodo = (todoObj) => {
    
    
    //获取原todos
    const {
    
     todos } = this.state
    //在数组前方追加一个todo
    const newTodos = [todoObj, ...todos]
    //更新状态
    this.setState({
    
     todos: newTodos })
}

<Header addTodo={
    
    this.addTodo} />

Header.jsx

//绑定回车事件
<input onKeyUp={
    
    this.handleKeyUp} type="text" placeholder="请输入你的任务名称,按回车键确认" />

//绑定事件的元素和要操作的元素相同,可以不用ref
handleKeyUp = (event) => {
    
    
    //回车键keycode是13,现在不推荐使用keyCode了,event.keyCode !== 13
    if (event.key !== 'Enter') return
    //添加的todo名字不能为空
    if (event.target.value.trim() === '') {
    
    
        alert('输入不能为空')
        return
    }
    //准备好新增的todoObj
    const todoObj = {
    
     id: nanoid(), name: event.target.value, done: false }
    //将todoObj传递给App(子给父)
    this.props.addTodo(todoObj)
    //清空输入框
    event.target.value = ''
}

insert image description here

mouse move in and out effect

Item.jsx

state = {
    
     mouse: false }

//鼠标移入移出的回调,高阶函数写法
handleMouse = (flag) => {
    
    
    //注意:回调中函数可以写小括号,但是无论什么情况都要给事件一个回调函数,返回值是函数耶ok
    return () => {
    
    
        this.setState({
    
     mouse: flag })
    }
}

<li style={
    
    {
    
     backgroundColor: this.state.mouse ? '#95b196' : 'white' }} onMouseEnter={
    
    this.handleMouse(true)} onMouseLeave={
    
    this.handleMouse(false)}>
	...
	<button className="btn btn-danger" style={
    
    {
    
     display: this.state.mouse ? 'block' : 'none' }}>删除</button>
</li>

insert image description here

Todo is checked, the focus is on changing the state

Get the id and check status of the item to be operated in the Item subcomponent—notify the App to update the state data (sun to father----pass layer by layer)

App.jsx

//更新todo对象---接收Item传过来的id和勾选
updateTodo = (id, done) => {
    
    
    //获取原状态的todos
    const {
    
     todos } = this.state
    //匹配处理数据
    const newTodos = todos.map((todoObj) => {
    
    
        //解构,然后相同的覆盖
        if (todoObj.id === id) return {
    
     ...todoObj, done: done }
        else return todoObj
    })
    //更新状态
    this.setState({
    
     todos: newTodos })
}
//给子组件List传递一个函数
<List todos={
    
    this.state.todos} updateTodo={
    
    this.updateTodo} />

List.jsx

//自己不用,反手就交给自己的子组件Item
const {
    
     todos, updateTodo } = this.props
return <Item key={
    
    todo.id} {
    
    ...todo} updateTodo={
    
    updateTodo} />

Item.jsx

//给勾选框绑定onChange事件,传入操作的id
<input type="checkbox" defaultChecked={
    
    done} onChange={
    
    this.handleCheck(id)} />

//勾选、取消勾选的回调
handleCheck = (id) => {
    
    
    //给input绑定,拿input的值,不需要ref,借助event即可
    //孙子组件给App传递数据
    return (event) => {
    
    
        this.props.updateTodo(id, event.target.checked)
    }
}

Summary: Where the state is, there is the method of manipulating the state
insert image description here

Limit props delivery

App passes data to Header and List, so limit the received data in Header and List components

Header.jsx and List.jsx

//引入
import PropTypes from 'prop-types'

//对接收的props进行:类型、必要性限制
static propTypes = {
    
    
    addTodo: PropTypes.func.isRequired
}
    
static propTypes = {
    
    
    todos: PropTypes.array.isRequired,
    updateTodo: PropTypes.func.isRequired
}

delete a todo

App.jsx

//删除一个todo
deleteTodo = (id) => {
    
    
    //获取原状态的todos
    const {
    
     todos } = this.state
    //删除指定id的todo对象
    const newTodos = todos.filter((todoObj) => {
    
    
        return todoObj.id !== id
    })
    //更新状态
    this.setState({
    
     todos: newTodos })
}
    
//准备好的函数给孙子组件传过去,一层一层传,借助子组件List
<List todos={
    
    this.state.todos} updateTodo={
    
    this.updateTodo} deleteTodo={
    
    this.deleteTodo} />

List.jsx

//反手交给Item,可以先解构
return <Item key={
    
    todo.id} {
    
    ...todo} updateTodo={
    
    updateTodo} deleteTodo={
    
    deleteTodo} />

Item.jsx

//绑定事件
<button onClick={
    
    () => this.handleDelete(id)} className="btn btn-danger" style={
    
    {
    
     display: this.state.mouse ? 'block' : 'none' }}>删除</button>

//删除一个todo的回调,非高阶写法
handleDelete = (id) => {
    
    
    if (window.confirm('确定删除吗?')) {
    
    
        this.props.deleteTodo(id)
    }
}

insert image description here

Bottom Footer

defaultChecked can only take effect at the first time, after modification there is no responsedefaultChecked={doneCount === total ? true : false}

defaultChecked is actually pretty tricky! ! !

checked will report an error and requires onChange
insert image description here

<input type="checkbox" onChange={this.handleCheckAll} checked={doneCount === total ? true : false} />

First complete the simple select all button

App.jsx

//全选
checkAll = (done) => {
    
    
    //获取原状态的todos
    const {
    
     todos } = this.state
    //加工数据
    const newTodos = todos.map((todoObj) => {
    
    
        return {
    
     ...todoObj, done: done }
    })
    //更新状态
    this.setState({
    
     todos: newTodos })
}
//传过去
<Footer todos={
    
    this.state.todos} checkAll={
    
    this.checkAll} />

Footer.jsx

//已完成个数--条件统计
const doneCount = todos.reduce((pre, todo) => {
    
     return pre + (todo.done ? 1 : 0) }, 0)
//总数
const total = todos.length
//展示数据
<span>已完成{
    
    doneCount}</span> / 全部{
    
    total}


//写成defaultChecked会有bug(仅在第一次可以),写成checked会警告,所以写成回调形式
//全选checkbox的回调
handleCheckAll = (event) => {
    
    
    this.props.checkAll(event.target.checked)
}
    
<input type="checkbox" onChange={
    
    this.handleCheckAll} checked={
    
    doneCount === total && total !== 0 ? true : false} />

Then write clear done button function

App.jsx

//清除已完成的
clearChecked = () => {
    
    
    //获取原状态的todos
    const {
    
     todos } = this.state
    const newTodos = todos.filter((todoObj) => {
    
    
        return todoObj.done === false
    })
    //更新状态
    this.setState({
    
     todos: newTodos })
}
//传过去
<Footer todos={
    
    this.state.todos} checkAll={
    
    this.checkAll} clearChecked={
    
    this.clearChecked} />

Footer.jsx

//清除已完成
handleClearChecked = () => {
    
    
    this.props.clearChecked()
}

<button onClick={
    
    this.handleClearChecked} className="btn btn-danger">清除已完成任务</button>

Fully functional demo

insert image description here

Guess you like

Origin blog.csdn.net/m0_55644132/article/details/127720177