react 父组件怎么获取子组件的这个值?


react 父组件怎么获取子组件的这个price值?
父组件:

class Flight extends Component{
    render() {
    return (
      <div>
        <Item />
      </div>
    )
  }
}

子组件:

export default class Item extends Component {
  constructor(props) {
    super(props);
    this.state = {
      names: ["(1)免费行李","2","3"],
      values: ["1","2","3"],
      selectName: '',
      prices: '0'
    }
  }

  handleChange(e){
    var value = e.target.value;
    var price = 800;
    if(value == "1"){
      price = 0
    }else{
      price = (value - 1) * price
    }
    this.setState({
      selectName: value,
      prices: price
    })
    //这个值怎么传给父组件
    console.log(price)
  }

  render() {
    var options = [];
    var prices = this.state.prices;
    for (var option in this.state.names) {
      options.push(
        <option key={this.state.values[option]} value={this.state.values[option]}> {this.state.names[option]}</option>
      )
    };
    return (

          <div className={styles.item}>
              <select className={styles.select} onChange={this.handleChange.bind(this)}> 
               {options}
              </select>
             <p>{prices}</p>
          </div>
        )
  }
}

求解。


概念上,组件是封闭的资料环境。React中是单向资料流的设计,也就是是说只有父组件传递资料给子组件这回事。以正确的技术说明,是 拥有者组件 可以设置 被拥有者组件 中的资料,也就是主人与仆人的关系。

那么子组件要如何与父组件沟通这件事,简单的来说,是一种迂回的作法,在父组件中设置了一个方法(函数),然后传递给子组件的props,子组件在事件触发时,直接呼叫这个props所设置的方法(函数)。但这中间,有谁(对象)呼叫了函数的设置,也就是this要对得住,对不到正确的对象,就不会正常作用。

父组件到子组件用props设置,子组件到父组件用上面说的方式,这是基本的套路,但它只适用于简单的组件结构,因为它相当麻烦,而且不灵活。那么如果要作到子组件与子组件要彼此沟通这件事,就不是太容易。当然,我想你已经听过,复杂的应用需要额外使用flux或redux来解决这问题,这是必经之路。

不过,在思考整体的React应用设计时,要有应用领域状态,也就是全局状态的概念。第一是应用领域state(状态)的,通常会在父组件中,而不是子组件中,子组件有可能很多,位于树状结构很深的地方。当然你这应用还简单,但思维总是要慢慢建立。

上面原理说完了,看代码应该会更佳理解,下面你的例子再简化一下的例子:

这是你的Item组件:

import React, { Component } from 'react'

export default class Item extends Component {
  constructor(props) {
    super(props)

    this.state = {
      names: ['(1)免费行李','2','3'],
      values: ['1','2','3'],
      selectName: '',
      prices: '0'
    }
  }

  handleChange(e){
    var value = e.target.value;
    var price = 800;
    if(value == '1'){
      price = 0
    }else{
      price = (value - 1) * price
    }
    this.setState({
      selectName: value,
      prices: price
    })
    //这个值怎么传给父组件
    //用传过来的changePrice属性(props),是个函数,呼叫它把price交给父组件中的函数去处理
    this.props.changePrice(price)
  }

  render() {
    var options = [];
    var prices = this.state.prices;
    for (var option in this.state.names) {
      options.push(
        <option key={this.state.values[option]} value={this.state.values[option]}> {this.state.names[option]}</option>
      )
    }

    return (
          <div>
              <select onChange={this.handleChange.bind(this)}>
               {options}
              </select>
             <p>{prices}</p>
          </div>
        )
  }
}

这是父组件,我用App.js代表:

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

class App extends Component {
  constructor(props) {
    super(props)

    this.state = {price: 0}
  }
  
  //给子组件用来传price用的方法
  changePrice(price){
    this.setState({price: price})
  }

  render() {
    return (
      <div>
        <Item changePrice={this.changePrice.bind(this)}/>
        <p>{this.state.price}</p>
      </div>
    );
  }
}

export default App;

上面解决了你的问题。但下面是我想多写的,因为代码中有很多撰写风格的问题。要一步就到位当然不可能,可以渐进式来作。

1. 先绑定(bind)住render有用到的方法

在父组件与子组件各有用到一个自己的方法changePrice,并在render中作赋值,在React中需要bind过才会把this对住,因为在render的return语句中使用,它在重渲染(re-render)时会再次建立新的方法(函数)内容值,这样会有效能上的影响,所以要先作绑定的事,然后再render的return里面用。

先绑定要在类的contructor里作,像下面这样,我这写一个父组件而已,子组件一样:

constructor(props) {
    super(props)

    this.state = {price: 0}

    //先bind类中方法
    this.changePrice = this.changePrice.bind(this)
  }

之后在render的return要改成这样:

render() {
    return (
      <div>
        <Item changePrice={this.changePrice}/>
        <p>{this.state.price}</p>
      </div>
    );
  }

这是其中的一种作法,另一种作法可以参考我在另一篇回答: https://.com/q/10...

2. 校正state(状态)里的资料,以及提升到父组件去

在子组件中的state(状态)中的资料是不是有那么必要放在子组件中,如果你还有第二个子组件、第三、第四…,它们都要用例如这里的选中资料,你放在这个子组件是违反了上面说的应用领域全局资料思维的。

先看一下子组件目前的state,是长这个样子:

this.state = {
      names: ['(1)免费行李','2','3'],
      values: ['1','2','3'],
      selectName: '',
      prices: '0'
    }

这里要先校正一下,names与values是代表选项中的名与值,它们是有关联的,所以应该是这样的下面结构才是好些的,value如果是要用来代表数字,就用数字就行不需要用字串:

options: [
  {name:'(1)免费行李', value: 1 },
  {name:'2', value: 2 },
  {name:'3', value: 3 }
]

选中了哪个选项这个状态资料,还是要先放在子组件中,因为子组件中有选项盒,与触发的更动方法,但选项的资料可以移到上层的父组件中:

这是上层App.js中的状态:

this.state = {
   options: [
        {name:'(1)免费行李', value: 1 },
        {name:'2', value: 2 },
        {name:'3', value: 3 }
   ],
   price: 0
}

父组件也改用把state里面的选项值,用props值给子组件,所以在render里语句改成下面这样:

render() {
    return (
      <div>
        <Item changePrice={this.changePrice} optionArray={this.state.options}/>
        <p>{this.state.price}</p>
      </div>
    )
  }

子组件中这时可以用this.props.optionArray接到传入的选项值,所以在render方法中,改用这个来代替之前的this.state.names与this.state.values,简单改写如下:

  var options = []
  var prices = this.state.prices
  var optionArray = this.props.optionArray

  for (var i = 0; i< optionArray.length; i++) {
      options.push(
        <option key={i} value={optionArray[i].value} >
          {optionArray[i].name}
        </option>
    )
   }

注: 这里不用for...in语句而用for语句,是因为for...in语句是个不建议用在数组资料的语法,它并不会保证取到数组成员里的顺序。for...in只会用在对象的寻遍中。

更精简的写法是用Array.map,如下:

var options = []
var prices = this.state.prices
var optionArray = this.props.optionArray

options = optionArray.map(function(item, index){
   return (
     <option key={index} value={item.value} >
         {item.name}
     </option>
   )
})

接著,如果依选项选中然后计算价格这件事,规划中应该是整个应用来作的,例如有可能还有其他的组件中也有其他的选项,最后统一要来算价格,所以计算价格这件事,也应该放到父组件去,所以如同上面的改写一样,把子组件的prices状态与相关计算的代码,都提到父组件,这个子组件纯用来当选项盒用而已。子组件此时连state都可以不用有。

因为整个改写过的代码会多些,所以我把父组件与子组件中的代码整个贴上。

父组件App.js:

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

export default class App extends Component {
  constructor(props) {
    super(props)

    this.state = {
      options: [
        {name:'(1)免费行李', value: 1 },
        {name:'2', value: 2 },
        {name:'3', value: 3 }
      ],
      price: 0
    }
    this.changePrice = this.changePrice.bind(this)
  }

  changePrice(value){
    var price = 800;

    if(value === 1) price = 0
    else price = (value - 1) * price

    this.setState({price: price})
  }

  render() {
    return (
      <div>
        <Item changePrice={this.changePrice} optionArray={this.state.options}/>
        <p>{this.state.price}</p>
      </div>
    )
  }
}

子组件Item.js:

import React, { Component } from 'react'

export default class Item extends Component {
  constructor(props) {
    super(props)
    this.handleChange = this.handleChange.bind(this)
  }

  handleChange(e){
    this.props.changePrice(e.target.value)
  }

  render() {
    var options = []
    var optionArray = this.props.optionArray

    options = optionArray.map(function(item, index){
      return (
        <option key={index} value={item.value} >
             {item.name}
       </option>
      )
    })

    return (
          <div>
              <select onChange={this.handleChange}>
               {options}
              </select>
          </div>
        )
  }
}

3. 目前最终进化版本

这个版本有几个改进如下,供参考:

  • let/const取代var

  • 不用分号(;)作为语句结尾。

  • Item子组件改用函数定义方式,取代原先的组件定义方式。

  • 能合并的语句都合并。

  • 函数全用箭头函数(注意需额外加装babel-plugin-transform-class-properties)。

App.js

import React, { Component } from 'react'
import Item from './Item2'

export default class App extends Component {
  constructor(props) {
    super(props)

    this.state = {
      options: [
        {name:'(1)免费行李', value: 1 },
        {name:'2', value: 2 },
        {name:'3', value: 3 }
      ],
      price: 0
    }

  }

  changePrice = (value) => {
    let price = 800

    if(value === 1) price = 0
    else price *= value - 1

    this.setState({price: price})
  }

  render() {
    return (
      <div>
        <Item changePrice={this.changePrice} optionArray={this.state.options}/>
        <p>{this.state.price}</p>
      </div>
    )
  }
}

Item.js

import React from 'react'

const Item = (props) => {
  const optionArray = props.optionArray
  const options = optionArray.map((item, index) => {
    return (
      <option key={index} value={item.value} >
           {item.name}
     </option>
    )
  })

  return (
        <div>
            <select onChange={e => {props.changePrice(e.target.value)}}>
             {options}
            </select>
        </div>
  )
}

export default Item

父组件获取子组件的值可以通过回调来完成
父组件

子组件

当然你也可以使用https://github.com/mroderick/... 发布订阅模式JS库


  1. callback

  2. ref


关于子组件向父组件传值,楼上的答案已经说明白了,那就是传一个方法进去,用callback的方式调用;
对于题主使用this.setState报错,除了像枯叶那样使用“var self = this”之外,还可以试试用bind:

    constructor(props) {
      super(props);
      this.state = { a: '' };
      this.fn = this.fn.bind(this);
    }

这样也能在fn()中使用this.setState而不会报错


可以用函数传值,大概是这样:

// 父组件
class P extends Component {
    fn(newState) {
        this.setState({ someKey: newState });
    }
    render() {
        return (
            <Child pfn={this.fn} />
        );
    }
}

// 子组件
class Child extends Component {
    someFn() {
        this.props.pfn(newState); // 传给父组件了
    }
    render() {
        return (
            <div></div>
        );
    }
}



相关阅读:
react,多个节点执行同一个事件,怎么区分启动事件的是哪个节点?
跨域修改css样式
mac下用chrome浏览器和safiri运行总是出问题?
列表分割数据输出
关于django model relation set的设置问题
新闻类app,每次上拉和下拉刷新都有数据,逻辑是怎样的,如何防止重复?
ios系统cursor: pointer失效
谁能用通俗易懂的言语解释一下区块链中的节点和区块的意思啊
怎么取出排序后字典中的第一个键值对
position定位,设置top为百分数,如何计算?
python 中文写入文件后乱码
jquery实现鼠标滚动时元素消失,不滚动的时候元素回来?
vue2函数化组件的问题
Spring data elasticsearch注解@Filed和@ManytoMany同时使用,搜索结果取到属性为null
前端项目使用module.exports文件一定要Webpack编译吗?请问gulp可以编译这种文件吗
vuejs 如何在组件内调用腾讯地图的API
macbook用终端安装cocoapods时出问题 后来“gem”指令失效
js能监听伪元素的transitionend吗?
微信开发文档第三步:刷新access_token这个有什么用
表格填写数据,前后为什么会发生变化



快速导航
PHP MySQL HTML CSS JavaScript MSSQL AJAX .NET JSP Linux Mac ASP 服务器 SQL jQuery C# C++ java Android IOS oracle MongoDB SQLite wamp 交通频道 作文范文 杂志社个人上半年工作总结 企业是我家的演讲稿 普外科护士实习鉴定 高中高二作文1000字:季节的思念 文化广播电视体育局工作总结和工作计划 草原之旅作文800字 党员先进性教育活动工作调查摸底报告_[实习报告] 带薪实习保证书 老婆没文化,原来很可怕 笑破肚皮 老师夸奖我作文600字 法院科学发展观民主生活会发言 我是个乖孩子作文 故事,在经年里蹉跎成一道明媚的阳光 叛逆作文500字 粮食收储公司成立五周年演讲:我与公司一起成长 计生工作责任书 初中初一作文300字:腊梅给我上了一堂课 学会了坚强作文700字 建党90周年心得体会 小学四年级作文450字:啊!我成功了 九年级班主任学生评语 牛逼霸气人生励志语录 端午节来了作文600字 一个人的寂寞,一个人的灯光 2016年度学校安全工作计划 汉口江滩公园作文 保护自己的眼睛 2014年市统计局工作总结范文 建党90周年单位党支部庆七一活动演讲稿 时间流逝(遗忘往事)作文500字 房屋产权登记委托书 邂逅,那一抹绿色的芬芳 HowWeSpentTeachersDay(我们怎样过教师节),HowWeSpentTea 服务质量承诺书怎么写 清明节问候短信大全 小时代金典语录 美在那一方作文 端午节感想_最美的风景 让我头疼的一件事 呼兰河传第三章读后感 国庆节的作文500字:国庆畅想 月季花与塑料花作文300字 【淡夏】---影少 我与奥运同行作文600字 【精品】《雷鸣电闪波尔卡》教学反思 财政系统治理商业贿赂工作必须坚持五个结合 诚信作文700字 杜甫《孤雁》诗歌鉴赏3 白露健脾润燥汤 我变成了老鼠

Copyright © 2016 phpStudy |