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:引用

posted on 2024-01-12 16:43  风zk  阅读(11)  评论(0编辑  收藏  举报

导航