React使用 - 组件通信

1、补充state与setState
state是组件自身 的状态
setState(updater, [callback])
updater: 更新数据 FUNCTION/OBJECT
callback: 更新成功后的回调 FUNCTION
浅合并 Object.assign()
数据需要修改,同时页面又要响应变化,使用 setState()方法来更新数据

import React, { Component } from 'react';
export default class App extends Component {
  state = {
    num: 1,
    name: '贝多芬',
    works: '命运交响曲',
    city: '罗马'
  }
  
  render() {
    let { num, name, works, city, country } = this.state;
    return (
      <div>
        <p>{num}</p>
        <p>{name}</p>
        <p>{works}</p>
        <p>{city}</p>
        <p>{country}</p>
        <button onClick={
          () => {
            // 此时,调用this.setNum()只是修改了值,还未进行渲染,
            // 当最后一个方法调用完成后,统一进行页面渲染
            this.setNum()
            this.setCountry()
            this.setCity()
          }
        }>
          点击更新数据
        </button>
      </div>
    )
  }
}

添加state的属性

  // 添加属性country
  setCountry = () => {
    this.setState({
      country: '意大利'
    });
  }

修改state的属性

  // 修改属性num
  setNum = () => {
    this.setState({
      num: this.state.num + 1
    });
  }

删除state的属性

  // 删除属性
  // 方法一:给要删除的那个属性赋值underfined或给它一个空字符串,这时这个属性还在,只是没有输出值
  // setCity = () => {
  //   this.setState({
  //     city: undefined
  //     // city:""
  //   })
  //   console.log(this.state.city);
  // }
  
  // 方法二:使用delete删除,把该属性及其属性值都删除了
  setCity = () => {
    this.setState((preState, props) => {
      delete preState.city;
      return preState;
    });
  }

注意:

  • 通过setState去更新this.state,不要直接操作this.state,请把它当成不可变的;
  • 调用setState更新this.state后,并不会立刻生效去渲染页面,它是异步的;
  • 如果有多个顺序执行的setState,它们会一个一个加入队列,然后统一一起执行,最后才去渲染页面,以保证渲染性能。

2、React组件间数据传递
在 React.js 中,数据是从上自下流动(传递)的,也就是一个父组件可以把它的 state / props 通过 props 传递给它的子组件,但是子组件不能修改 props - React.js 是单向数据流,

  • 子组件需要修改父组件状态(数据),是通过回调函数方式来完成的。
    父级向子级通信: 把数据添加子组件的属性中,然后子组件中从props属性中,获取父级传递过来的数据
  • 子级向父级通信: 在父级中定义相关的数据操作方法(或其他回调), 把该方法传递给子级,在子级中调用该方法父级传递消息

子组件
Child.js

import React, { Component } from 'react';
import Child from './Child';
export default class App extends Component {
  state = {
    name: '松花跑蛋',
    price: 14
  }
  // 在父组件中定义函数修改state属性
  changeValue = (newName, newPrice) => {
    this.setState({
      name: newName,
      price: newPrice
    });
  }
  render() {
    // 解构父组件自身的state
    let { name, price } = this.state;
    return (
      <div>
        <p>{name}</p>
        <p>{price}</p>
        <FriendList
          // 调用函数时需要this,传递给子组件后,在子组件中就可以直接使用
          changeValue={this.changeValue}
        />
      </div>);
  }
}

父组件
App.js

import React, { Component } from 'react';
export default class Child extends Component{
   render(){
       // 子组件中从props属性中,获取父级传递过来的changeValue函数
       let {changeValue} = this.props;
       return(
        <div>
            <button onClick={
                ()=>{
                    changeValue("酸辣土豆丝",12);
                }}>
                点击更新数据
            </button>
        </div>
       );
   }
} 

好友列表案例https://blog.csdn.net/m0_45315697/article/details/107046335
再次优化,

  • 当点击列表中每一个分组项时,当前分组项内容展开,其他项收起来;
  • 注意这里要判断点击当前项的状态,如果第一次点击内容(如果当前的展开,点击后就收起来;如果当前收起来,点击就展开)。

具体修改如下:
App.js

import React, { Component } from 'react';
import FriendList from './FriendList';
export default class App extends Component {
  render() {
    return (
      <div>
        <FriendList/>
      </div>
      );
  }
}

FriendList.js

import React, { Component } from 'react';
import './FriendList.css';//导入样式
import data from './data.js';//导入数据
import Dl from './dl.js';//导入分组列表

export default class FriendList extends Component {
    state = {
        // 表明哪一项是展开的
        isOpen: ''
    }
    
    // 传递给子组件,点击哪个子组件,子组件就将自己的name传过去
    changeOpen = (name) => {
        this.setState({ isOpen: name });
    }

    render() {
        // 自身的state
        let { isOpen } = this.state;
        console.log(isOpen);
        
        return (         
                // 根据数据的数量,循环创建分组(第一层循环)-分组组件 
                <div className="friend-list">
                    {
                        Object.keys(data).map((item, index) => {
                            return (
                                <Dl
                                    key={index}
                                    // 属性名
                                    name={item}
                                    // 属性值
                                    value={data[item]}
                                    // 哪一项是展开的
                                    isOpen={isOpen}
                                    // 哪一项展开,将name传递给子组件
                                    changeOpen={this.changeOpen}
                                />
                            );
                        })
                    }
            </div>
        );
    }
}

Dl.js

import React, { Component } from 'react';
export default class Dl extends Component {
    render() {
        // 子组件只能通过 props 来获取父组件传过来的数据
        console.log(this.props);
        let { title, list } = this.props.value;
        let { name, isOpen, changeOpen } = this.props;

        return (
            // 根据分组时获取的数据,分组中的列表内容(第二层循环)-列表组件
            <div className={"friend-group" + (name === isOpen ? " expanded" : "")}>
                {/* 动态列表内容 */}
                <dt onClick={() => {
                    //判断点击的是不是当前的分组
                    if (name === isOpen) {
                        changeOpen("")
                    } else {
                        changeOpen(name)
                    }
                }}>
                    {title}
                </dt>
                {
                    // 不建议使用index作为组件key值
                    list.map((item, index) => {
                        return <dd key={index}>{item.name}</dd>
                    })
                }
            </div>
        );
    }
}

Context跨组件通信

import {createContext} from 'react';

let context = createContext();
let {Consumer,Provider}=context;

export default context;
export {Consumer,Provider};
  • 存数据
    用Provider标签包裹,那么唯一父级内所有项都可以接收到传来的数据
import React, { Component } from 'react';
import FriendList from './FriendList';
import {Provider} from './context';

export default class App extends Component {
  render() {
    return (
      <Provider value={{book:'《React从基础到精通》'}}>
        <div>
          <FriendList/>
        </div>
      </Provider>  
      )
  }
}
  • 取数据
    使用Cosumer标签包裹
    <Consumer>
       {value=>value.book}
    </Consumer>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值