繁体   English   中英

反应 setState不会更新子组件的状态

[英]React. setState does not update state of subcomponents

这是我的组件结构:ExchangeRateInput ExhangeRateValueInput ExhangeRateDialog

打开状态作为道具传递给ExhangeRateDialog 但是当我在ExchangeRateInput中将setState打开为true时, ExhangeRateDialog中似乎没有更改。 有人可以解释我在做什么错。

ExchangeRateInput

import { composeWithTracker, composeAll } from 'react-komposer';
import React from 'react';
import useContext from '../../../containers/useContext.jsx';
import ExchangeRateValueInput from './ExchangeRateValueInput.jsx';
import ExchangeRateDialog from '../dialogs/ExchangeRateDialog.jsx';

const composer = (props, onData) => {
  onData(null, {});
};

export class ExchangeRateInput extends React.Component { //Wrapper Component
  constructor(props) {
    super(props);
    this.state = {
      value: props.value || '',
      date: '',
      showDialog: props.showDialog || false,
    };
    this.onChange = this.onChange.bind(this);
  }

  onChange(event) {
    const value = event.target.value;

    this.setState({ value });
  }

  onOpenDialog() {
    let bool = true;
    this.setState({ showDialog: bool }, () => {
      console.log(this.state);
    });
  }

  render() {
    return (
      <div>
        <ExchangeRateValueInput onChange={this.onChange} openDialog={this.onOpenDialog.bind(this)} value={this.state.value} />
        <ExchangeRateDialog onChange={this.onChange} open={this.state.showDialog} />
      </div>
    );
  }
}

ExchangeRateInput.propTypes = {
  value: React.PropTypes.number,
  onChange: React.PropTypes.func,
  openExhangeRateDialog: React.PropTypes.func,
};

const ComposedExchangeRateInput = composeAll(
  composeWithTracker(composer),
  useContext()
)(ExchangeRateInput);

export default ExchangeRateInput;

ExchangeRateDialog

import React from 'react';
import FlatButton from 'material-ui/FlatButton';
import DatePicker from 'material-ui/DatePicker';
import Dialog from 'material-ui/Dialog';
import useContext from '../../../containers/useContext.jsx';

export class ExchangeRateDialog extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: '',
      date: '',
      open: props.open || false,
    };
    this.onDialogConfirm = this.onDialogConfirm.bind(this);
    this.onDateChange = this.onDateChange.bind(this);
  }

  onDateChange(date) {
    const value = this.getFakeExchangeRate(); // Replace functionallity with Meteor-method
    setTimeout(() => {
      this.setState({ date, value });
    }, 1100);
  }

  onDialogConfirm() {
    this.props.onDialogConfirm({
      value: this.state.value,
      date: this.state.date,
    });
  }

  getFakeExchangeRate() {
    return Math.random(1, 15);
  }

  actions() {
    return [
      <FlatButton
        label="Cancel"
        secondary
        onTouchTap={this.props.onDialogCancel}
      />,
      <FlatButton
        label="Ok"
        primary
        onTouchTap={this.onDialogConfirm}
        disabled={!this.state.value}
      />,
    ];
  }

  render() {
    return (
      <div >
        <Dialog
          title="Get exchange rate from Riksbanken"
          modal={false}
          open={this.state.open}
          actions={this.actions()}
          onRequestClose={this.props.onDialogCancel}
        >
            Choose a date.
          <div className="layout horizontal">
            <div className="flex">
              <DatePicker
                hintText="No date selected"
                onChange={(event, date) => this.onDateChange(date)}
                maxDate={new Date()}
              />
            </div>
            <div className="flex">
              <h3>{this.state.value ? `Exchange rate: ${this.state.value}` : null}</h3>
            </div>
          </div>
        </Dialog>
      </div>
    );
  }
}

ExchangeRateDialog.propTypes = {
  value: React.PropTypes.number,
  date: React.PropTypes.string,
  open: React.PropTypes.bool,
  onChange: React.PropTypes.func,
  onDialogCancel: React.PropTypes.func,
  onDialogConfirm: React.PropTypes.func,
};

export default ExchangeRateDialog;

ExchangeRateValueInput

import React from 'react';
import TextField from 'material-ui/TextField';
import IconButton from 'material-ui/IconButton';
import useContext from '../../../containers/useContext.jsx';

export class ExchangeRateValueInput extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: props.value || '',
      errorMessage: '',
    };
    this.onValueChange = this.onValueChange.bind(this);
  }

  onValueChange(event) {
    const value = event.target.value;
    let errorMessage = '';
    let returnValue = value;

    const isNumber = !isNaN(value); // TODO: Improve validation

    if (!isNumber) {
      errorMessage = 'Must be a number';
      returnValue = '';
    }

    this.setState({
      value,
      errorMessage,
    }, () => {
      this.props.onChange(returnValue);
    });
  }

  onOpenDialog() {
    console.log('hej');
    console.log(this.props);
    this.props.onOpenDialog;
  }

  style = {
    height: 72,
  };

  render() {
    return (
      <div className="layout horizontal" style={this.style}>
        <div
          className=""
        >
          <TextField
            floatingLabelText="Value"
            onChange={this.onValueChange}
            errorText={this.state.errorMessage}
            value={this.state.value}
          />
        </div>
        <div
          className="layout center layout horizontal"
        >
          <IconButton
            className="flex"
            tooltip="Get from Riksbanken"
            onClick={() => this.props.openDialog()}
          >
            <i className="material-icons">search</i>
          </IconButton>
        </div>
      </div>
    );
  }
}

ExchangeRateValueInput.propTypes = {
  value: React.PropTypes.number,
  onChange: React.PropTypes.func,
  openDialog: React.PropTypes.func,
};

export default ExchangeRateValueInput;

您要将valueExchangeRateInput传递到ExchangeRateValueInput ,但随后将其存储在ExchangeRateValueInput的内部状态中。 此时,它已与ExchangeRateInput完全断开连接。 因此,当ExchangeRateValueInput更新其状态时,其父级对此一无所知。

您可以重写内容,以便在根组件( ExchangeRateInput )中管理所有状态,并将该状态传递给仅引用道具而不是其内部状态的子级。 然后,当孩子需要更新状态时,他们可以调用您定义的某个事件(例如this.props.onChange东西)。 ExchangeRateInput将处理这些事件,并相应地更新其状态。

或者,您需要研究使用磁通量模式(例如,使用Redux之类的东西)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM