002*:React状态、属性、setState 异步同步
1:目录
1:状态初步尝试
2:map 映射循环渲染
3:todolist 状态跟新
4:卖座项目实战
5:setState异步同步问题
6:滚动视图
7:类组件的属性
8:函数组件的属性
9:属性和状态的区别
2:正文
1:状态初步尝试
/* 状态初步尝试:需要调用 set,get 方法,但是 react 中的属性不支持,所以使用了 state, setState 1: 状态管理 状态就是组件描述某种显示情况的数据,由组件自己设置和更改,也就是说由组件自己维护. 使用状态的目的就是为了在不同的状态下使组件的显示不同(自己管理) 2:this.props和this.state是纯js对象,在vue中,data属性是利用Object.defineProperty处理过的, 更改data的数据的时候会触发数据的getter和setter, 但是React中没有做这样的处理,如果直接更改的话,react是无法得知的,所以,需要使用特殊的更改状态的方法setState。 3:用状态管理 做一个收藏和取消收藏的案例 */ import React, { Component } from 'react' export default class StateComponent extends Component { // 1:声明状态 state = { isFavorite: true } render() { return ( <div> <h1>状态管理</h1> <button onClick={() => { // 2:更新状态,调用setState方法之后会重新调用render方法 this.setState({ isFavorite: !this.state.isFavorite }) // 3:根据状态进行赋值 } }>{this.state.isFavorite ? "收藏" : "取消收藏"}</button> </div> ) } }
2:map 映射循环渲染
/* 1: 用map映射循环渲染 */ import React, { Component } from 'react' export default class ForRenderItemComponent extends Component { render() { // 1: 定义数据源 var list = ["zhaoyang", "lisi", "wangwu"] /* 2:map循环渲染 对数据源进行 map 映射循环渲染, map 是一个函数,参数是一个回调函数,回调函数的参数有两个:item, index item: 当前循环的数据,index: 设置为 key */ var zujianList = list.map((item, index) => { return <li key={index}>{item}</li> }) var zujianList1 = list.map((item, index) => <li key={index}>{item}</li>) return ( <div> <ul> {/* 3: 循环渲染 */} {zujianList1} </ul> </div> ) } } /* react的哲学思想: 如无必要,勿增实体。 设置 key 的原因 为了列表的重用和重排,提高性能 理想的 key 值是唯一的 id 值。如果数据源没有唯一 id 值,用 index索引值。 */
3:TodoList 案例,增删更新状态、list 深 copy
/* todolist 案例 1: ref 引用 2:setState 更新状态 3: list深拷贝 4: 随机数的功能 5: 删除功能 6:条件渲染 7:富文本 */ import React, { Component } from 'react' export default class TodoListComponent extends Component { state = { contentList: [] } // 1: ref 引用 myRef = React.createRef() // 2:map循环渲染 render() { var zujianList = this.state.contentList.map((item, index) => { return (<li key={index}> {item} <button onClick={() => { this.delButtonClick(index) }}>删除</button> </li>) }) return ( <div> <input type='text' ref={this.myRef} /> <button onClick={() => { this.addFunc() }}>add</button> <ul>{zujianList}</ul> {/* 条件渲染 */} {this.state.contentList.length === 0 && <div>暂无数据</div>} {/* */} {/* 富文本 */} <div dangerouslySetInnerHTML={ { __html: '<h1>大标题</h1>' } }></div> </div> ) } // 添加功能 addFunc = () => { console.log(this.myRef.current.value) // 3: list深拷贝 // let list1 = [...this.state.contentList] let list1 = this.state.contentList.slice() list1.push(this.myRef.current.value) // 2:setState 更新状态 this.setState({ contentList: list1 }) } // 删除功能 delButtonClick = (index) => { /* 不要修改原先的状态,可能会造成不可预期的问题 需要对原先的数组进行深 copy, */ let list1 = this.state.contentList.slice() list1.splice(index, 1) // 2:setState 更新状态 this.setState({ contentList: list1 }) } }
4:卖座项目实战
1:MaiZuoComponent组件
/* 功能设计 1:底部选项卡 ' */ import React, { Component } from 'react' import "./css/02-maizuo.css" import Film from './maizuocomponent/Film' import Cinema from './maizuocomponent/Cinema' import MySetting from './maizuocomponent/MySetting' export default class MaiZuoComponent extends Component { state = { list: [ { id: 0, text: '电影', }, { id: 1, text: '影院', }, { id: 2, text: '我的', } ], activeIndex: 0, } render() { return ( <div> {this.showContentComponent(this.state.activeIndex)} <ul> { this.state.list.map((item, index) => ( <li key={item.id} className={this.state.activeIndex === index ? "active": ""} onClick={()=>{ this.setState({ activeIndex: index }) }}>{item.text}</li> )) } </ul> </div> ) } showContentComponent(index) { switch (index) { case 0: return <Film></Film> case 1: return <Cinema></Cinema> case 2: return <MySetting>我的</MySetting> default: return null } } }
2:Film组件
import React, { Component } from 'react' export default class Film extends Component { render() { return ( <div>Film</div> ) } }
3:Cinema组件
import React, { Component } from 'react' /* 1: 安装axios,用于发送ajax请求,第三方库,专门用于请求网络数据 npm i --save axios */ import axios from 'axios' export default class Cinema extends Component { myInputRef = React.createRef() constructor() { super() this.state = { cinemasList: [], editList: [] } // 简写部分 // axios.get("https://m.maizuo.com/gateway?cityId=110100&ticketFlag=1&k=4345146").then(res => { // console.log(res) // }).catch(err => { // console.log(err) // }) // 完整写法 axios({ method: 'get', url: "https://m.maizuo.com/gateway?cityId=110100&ticketFlag=1&k=4345146", headers: { 'X-Client-Info': '{"a":"3000","ch":"1002","v":"5.2.1","e":"17053742704302745481773057"}', 'X-Host': 'mall.film-ticket.cinema.list' } }).then(res => { // console.log(res) // 真正的后端数据 console.log(res.data.data.cinemas) this.setState({ cinemasList: res.data.data.cinemas, editList: res.data.data.cinemas }) }).catch(err => { console.log(err) }) } render() { return ( <div> <input onInput={() => { this.handleInputChange() }} ref={this.myInputRef}></input> { this.state.editList.map((item) => <dl key={item.cinemaId}> <dt>{item.name}</dt> <dd>{item.address}</dd> </dl>) } </div> ) } // 处理输入框内容变化 handleInputChange = () => { console.log(this.myInputRef.current.value) var newArray = this.state.cinemasList.filter((item) => { return (item.name.toUpperCase().includes(this.myInputRef.current.value.toUpperCase()) || item.address.toUpperCase().includes(this.myInputRef.current.value.toUpperCase())) }) this.setState({ editList: newArray }) } }
4:MySetting组件
import React, { Component } from 'react' export default class MySetting extends Component { render() { return ( <div>MySetting</div> ) } }
5:maizu.css
*{ margin: 0px; padding: 0px; } ul{ list-style: none; display: flex; position: fixed; bottom: 0px; left: 0px; height: 50px; line-height: 50px; width: 100%; background-color: white; } ul li { flex: 1; text-align: center ; } .active{ color: red; } dl { height: 60px; border-bottom: 1px solid #ccc; } dl dt { font-size: 20px; } dl dd { font-size: 14px; color: #ccc; } input { width: 100%; height: 50px; /* 文本垂直居中 */ line-height: 50px; font-size: 30px; }
5:setState异步同步问题
import React, { Component } from 'react' export default class SynAsynComponent extends Component { state = { count: 0 } render() { return ( <div> {this.state.count} <button onClick={() => { this.hanldeClick1() }}>add1</button> <button onClick={this.hanldeClick2}>add2</button> <button onClick={() => { this.hanldeClick3() }}>add3</button> </div> ) } hanldeClick1 = () => { this.setState({ count: this.state.count + 1 }) console.log(this.state.count) this.setState({ count: this.state.count + 1 }) console.log(this.state.count) this.setState({ count: this.state.count + 1 }) console.log(this.state.count) } hanldeClick2 = () => { setTimeout(() => { this.setState({ count: this.state.count + 1 }) console.log(this.state.count) this.setState({ count: this.state.count + 1 }) console.log(this.state.count) this.setState({ count: this.state.count + 1 }) console.log(this.state.count) }, 0) } hanldeClick3 = () => { this.setState({ count: this.state.count + 1 }, () => { console.log(this.state.count) }) this.setState({ count: this.state.count + 1 }, () => { console.log(this.state.count) }) this.setState({ count: this.state.count + 1 }, () => { console.log(this.state.count) }) } } /* setState是同步异步问题 1 . 异步情况 (1)在合成事件中 ,也就是react规定的onClick等事件中 setState是异步的 (2)在生命周期中setState也是异步的 2 . 同步情况 (1)在定时器中 setState是同步的 (2)在js原生事件中setState也是同步的 异步带来的问题 (1)累加问题,按照最后一个来处理 */
6:滚动视图
import React, { Component } from 'react' import BetterScroll from 'better-scroll' export default class BetterScrollComponent extends Component { state = { list: [], } render() { return ( <div> <button onClick={() => { this.handleClick() }}>添加数据源</button> {/* 外边 div 高度有限,内部高度无线,移出异常 */} <div className="wrapper" style={{ height: "200px", background: 'yellow', overflow: 'hidden' }}> <ul className="content"> { this.state.list.map(item => { return <li key={item}>{item}</li> }) } </ul> </div> </div> ) } handleClick = () => { // 方法一: this.setState({ list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] }, ()=> { // 需要等到数据渲染完毕后,再初始化better-scroll new BetterScroll(".wrapper") }) } }
7:类组件的属性
/* 组件的属性 组件中的属性就相当于 oc类中的属性 */ import React, { Component } from 'react' import NavBarComponent from './nav/NavBar' export default class PropsComponent extends Component { render() { return ( <div> <NavBarComponent title="首页"></NavBarComponent> <NavBarComponent title="电影院"></NavBarComponent> <NavBarComponent title="我"></NavBarComponent> </div> ) } }
NavBarComponent组件
/* 创建导航组件,接受父组件传递过来的title属性 */ import React, { Component } from 'react' export default class NavBarComponent extends Component { render() { return ( <div>{this.props.title}</div> ) } }
8:函数组件的属性
import React from 'react' export default function FunctionPropsComponent(props) { let { bg } = props console.log(props) return ( <div style={{ background: bg}}>15-函数组件的属性</div> ) }
9:属性和状态的区别
子组件中的属性,只可读取
子组件的状态,是私有变量,外部不可以访问。
10:受控组件
/* 一个输入框: 1. 输入框的内容内容受状态控制。 2:可以传递给子组件。 */ import React, { Component } from 'react' export default class ControlComponet extends Component { state = { value: '请输入内容' } render() { return ( <div> <input type='text' value={this.state.value} onChange={(event) => { this.setState({ value: event.target.value }) }} /> <button onClick={() => { console.log(this.state.value) }}>登录</button> <button onClick={() => { this.setState({ value: "" }) }}>重置</button> </div> ) } }
3:引用