专业编程基础技术教程

网站首页 > 基础教程 正文

react高质量笔记_11(组件的组合使用)

ccvgpt 2024-11-26 00:53:27 基础教程 1 ℃

由于代码太多,文章中的附件放置尾部

一、组件的组合使用-TodoList案例

1. 具体代码查看附件二

2. 注意点

1、父组件向子组件传数据:直接在子组件标签中添加键值对形式的数据(props)

react高质量笔记_11(组件的组合使用)

父组件:
<List todos={todos}}/>
子组件使用:
const {todos} = this.props

2、子组件向父组件传递数据:父组件通过props给子组件传递一个函数,子组件在想要传递数据给父组件时,调用该函数

? 父组件给子组件一个调用的函数

<Header addTodo={this.addTodo}/>

? 子组件调用父组件函数

handleKeyUp = (event)=>{
  //准备好一个todo对象
  const todoObj = {id:nanoid(),name:target.value,done:false}
  //将todoObj传递给App
  this.props.addTodo(todoObj)
}

3、生成时间戳:Date.now()

UUID:生成唯一时间戳的库

npm i uuid (库比较大)

npm i nanoid(库小,很快安装)/ yarn add nanoid

用法:

import {nanoid} from 'nanoid'

调用:

nanoid( )

4、在react中,<input type="checkbox"/>若加了checked属性,则必须加onChange事件,不然无法改变勾选状态。defaultChecked只在第一次起效果。

3. todoList案例相关知识点

1.拆分组件、实现静态组件,注意:className、style的写法

2.动态初始化列表,如何确定将数据放在哪个组件的state中?

某个组件使用:放在其自身的state中

某些组件使用:放在他们共同的父组件state中(官方称此操作为:状态提升)

3.关于父子之间通信:

1.【父组件】给【子组件】传递数据:通过props传递

2.【子组件】给【父组件】传递数据:通过props传递,要求父给子传递一个函数

4.注意defaultChecked 和 checked的区别,类似的还有:defaultValue 和 value

5.状态在哪里,操作状态的方法就在哪里

二、react配置代理

1. 单一配置

在package.json中追加如下配置

"proxy":"http://localhost:5000"

说明:

1. 优点:配置简单,前端请求资源时可以不加任何前缀。

2. 缺点:不能配置多个代理。

3. 工作方式:上述方式配置代理,当请求了3000不存在的资源时,那么该请求会转发给5000 (优先匹配前端资源)

2. 多服务配置

? 创建代理配置文件

在src下创建配置文件:src/setupProxy.js

? 编写setupProxy.js配置具体代理规则

const proxy = require('http-proxy-middleware')
module.exports = function(app) {
  app.use(
    //api1是需要转发的请求(所有带有/api1前缀的请求都会转发给5000)
    proxy('/api1', {
      target: 'http://localhost:5000',//配置转发目标地址(能返回数据的服务器地址)
      changeOrigin: true, //控制服务器接收到的请求头中host字段的值
      //changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000; changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:3000;changeOrigin默认值为false,但我们一般将changeOrigin值设为true
      pathRewrite: {'^/api1': ''} //去除请求前缀,保证交给后台服务器的是正常请求地址(必须配置)
     }),
     proxy('/api2', {
      target: 'http://localhost:5001',
      changeOrigin: true,
      pathRewrite: {'^/api2': ''}
    })
  )
}

说明:

1. 优点:可以配置多个代理,可以灵活的控制请求是否走代理。

2. 缺点:配置繁琐,前端请求资源时必须加前缀。

附件二:todoList案例代码

1. APP.css

.btn:focus {
 outline: none;
}

.todo-container {
 width: 600px;
 margin: 0 auto;
}
.todo-container .todo-wrap {
 padding: 10px;
 border: 1px solid #ddd;
 border-radius: 5px;
}

2. APP.js

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

class App extends Component {
   state = {
     todos:[
       {id:'001',name:'吃饭',done:true},
       {id:'002',name:'睡觉',done:true},
       {id:'003',name:'打代码',done:false},
       {id:'004',name:'逛街',done:false}
     ]
   }
   //添加数据
   addTodo = (data)=>{
     const {todos} = this.state
     this.setState({todos:[data, ...todos]})
   }
   //勾选数据
   checkTodo = (id,done)=>{
     const {todos} = this.state
     const newTodos = todos.map(item=>{
       if(item.id === id) return {...item,done}
       else return item
     })
     this.setState({todos: newTodos})
   }
   //删除单条数据
   deleteTodo = (id)=>{
     const { todos } = this.state
     //赛选数据
     const newTodos = todos.filter(item=>item.id !== id)
     //重新赋值
     this.setState({todos: newTodos})
   }
   //全选/全不选
   checkAllTodo = (done)=>{
     const { todos } = this.state
     const newTodos = todos.map(item=>{
    	 return {...item,done}
     })
     this.setState({todos:newTodos})
   }

   //清空已选择
   clearCheckedTodo = ()=>{
     const { todos } = this.state
     const newTodos = todos.filter(item=> !item.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} checkTodo={this.checkTodo} deleteTodo={this.deleteTodo}/>
           {/*底部*/}
           <Footer todos={todos} checkAllTodo={this.checkAllTodo} clearCheckedTodo={this.clearCheckedTodo}/>
         </div>
       </div>
     );
   }
}

export default App;

3. Header.css

/*footer*/
.todo-footer {
 height: 40px;
 line-height: 40px;
 padding-left: 6px;
 margin-top: 5px;
}

.todo-footer label {
 display: inline-block;
 margin-right: 20px;
 cursor: pointer;
}

.todo-footer label input {
 position: relative;
 top: -1px;
 vertical-align: middle;
 margin-right: 5px;
}

.todo-footer button {
 float: right;
 margin-top: 5px;
}

4. Header.jsx

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

class Header extends Component {
   //类型限制
   static propTypes = {
   	addTodo:PropTypes.func.isRequired
   }
   //键盘事件回调
   handleKeyUp = (event)=>{
     //解构赋值获取keyCode,target
     const {keyCode, target} = event
     //判断是否是回车键
     if (keyCode == 13){
       //获取值
       const val = target.value
       if(val.trim() === ''){
       alert('输入的值不能为空')
       return
       }
       //创建一个对象
       const todoObj = {id:nanoid(), name:val, done:false}
       //将数据传递给APP组件
       this.props.addTodo(todoObj)
       //清空数据
       target.value = ''
     }

     }

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

export default Header;

5. List.css

/*main*/
.todo-main {
 margin-left: 0px;
 border: 1px solid #ddd;
 border-radius: 2px;
 padding: 0px;
}

.todo-empty {
 height: 40px;
 line-height: 40px;
 border: 1px solid #ddd;
 border-radius: 2px;
 padding-left: 5px;
 margin-top: 10px;
}

6. List.js

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

class List extends Component {
   //对传入的数据进行限制
   static propTypes = {
     todos:PropTypes.array.isRequired,
     deleteTodo:PropTypes.func.isRequired,
     checkTodo:PropTypes.func.isRequired
   }
   render() {
     const {todos,checkTodo, deleteTodo} = this.props
     return (
       <ul className="todo-main">
         {
           todos.map(item=>{
           	return <Item key={item.id} todo={item} checkTodo={checkTodo} deleteTodo={deleteTodo}/>
           })
         }
       </ul>
     );
   }
}

export default List;

7. Item.css

/*item*/
li {
 list-style: none;
 height: 36px;
 line-height: 36px;
 padding: 0 5px;
 border-bottom: 1px solid #ddd;
}

li label {
 /*float: left;*/
 cursor: pointer;
}
li label span{
 margin-left: 10px;
}

li label li input {
 vertical-align: middle;
 margin-right: 6px;
 position: relative;
 top: -1px;
}

li button {
 float: right;
 display: none;
 margin-top: 3px;
}

li:before {
 content: initial;
}

li:last-child {
 border-bottom: none;
}

8. Item.js

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

class Item extends Component {
   state = {
   	mouse:false //标识鼠标移入移除
   }
   //鼠标移入移除
   handleMouse = (flag)=>{
     return ()=>{
     	this.setState({mouse:flag})
     }
   }
   //删除
   handleDelete = (id)=>{
     return ()=>{
       if(window.confirm('是否确认删除?')){
         const {deleteTodo} = this.props
         deleteTodo(id)
       }
     }
   }
   //勾选
   handleCheck = (id)=>{
     return (event)=>{
     	this.props.checkTodo(id, event.target.checked)
     }
   }
   render() {
     //接收list的值
     const {id, name, done} = this.props.todo
     const {mouse} = this.state
     return (
       <li style={{backgroundColor: mouse ? '#ddd' : 'white'}} onMouseEnter={this.handleMouse(true)}
         onMouseLeave={this.handleMouse(false)}>
         <label>
         <input type="checkbox" onChange={this.handleCheck(id)} checked={done}/>
         <span>{name}</span>
         </label>
         <button className="btn btn-danger" style={{display:mouse?'block':'none'}}
         onClick={this.handleDelete(id)}>删除</button>
       </li>
     );
   }
}

export default Item;

9. Footer.css

/*footer*/
.todo-footer {
 height: 40px;
 line-height: 40px;
 padding-left: 6px;
 margin-top: 5px;
}

.todo-footer label {
 display: inline-block;
 margin-right: 20px;
 cursor: pointer;
}

.todo-footer label input {
 position: relative;
 top: -1px;
 vertical-align: middle;
 margin-right: 5px;
}

.todo-footer button {
 float: right;
 margin-top: 5px;
}


10. Footer.js

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

class Footer extends Component {
   //全选/全不选
   checkAllTodo = (event)=>{
   	this.props.checkAllTodo(event.target.checked)
   }
   //清空已选择数据
   clearCheckedTodo = ()=>{
   	this.props.clearCheckedTodo()
   }
   render() {
     const {todos} = this.props
     //已完成数
     const doneCount = todos.reduce((pre, todo)=> pre + (todo.done?1:0),0)
     //总数
     const c = todos.length
     return (
       <div className="todo-footer">
         <label>
         <input type="checkbox" onChange={this.checkAllTodo} checked={doneCount === c && c !== 0? true:false}/>
         </label>
         <span>
         <span>已完成{doneCount}</span> / 全部{c}
         </span>
         <button className="btn btn-danger" onClick={this.clearCheckedTodo}>清除已完成任务</button>
       </div>
     );
   }
}

export default Footer;

结语:

把所有美好都给你

你值得

我愿意

回复react笔记,可以获得全套笔记

react高质量笔记_10(React脚手架)

react高质量笔记_9(Diffing算法)

Tags:

最近发表
标签列表