简体   繁体   English

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

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

This is my component-structure: ExchangeRateInput ExhangeRateValueInput ExhangeRateDialog 这是我的组件结构:ExchangeRateInput ExhangeRateValueInput ExhangeRateDialog

The state open in is passed through to ExhangeRateDialog as a prop. 打开状态作为道具传递给ExhangeRateDialog But when i setState open to true in ExchangeRateInput it doesnt seem to change in ExhangeRateDialog . 但是当我在ExchangeRateInput中将setState打开为true时, ExhangeRateDialog中似乎没有更改。 Can someone please explain what i am doing wrong. 有人可以解释我在做什么错。

ExchangeRateInput 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 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 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;

You're passing value from ExchangeRateInput to ExchangeRateValueInput , but then you're storing it in the internal state of ExchangeRateValueInput . 您要将valueExchangeRateInput传递到ExchangeRateValueInput ,但随后将其存储在ExchangeRateValueInput的内部状态中。 At this point, its completely disconnected from ExchangeRateInput . 此时,它已与ExchangeRateInput完全断开连接。 So, when ExchangeRateValueInput updates its state, its parent knows nothing about it. 因此,当ExchangeRateValueInput更新其状态时,其父级对此一无所知。

You could rewrite things so that all state is managed in the root component ( ExchangeRateInput ) and it passes that state down to the children who only reference props, rather than their own internal state. 您可以重写内容,以便在根组件( ExchangeRateInput )中管理所有状态,并将该状态传递给仅引用道具而不是其内部状态的子级。 Then, when the children need to update state, they can call some event that you define (eg this.props.onChange or something). 然后,当孩子需要更新状态时,他们可以调用您定义的某个事件(例如this.props.onChange东西)。 ExchangeRateInput would handle those events, and update its state accordingly. ExchangeRateInput将处理这些事件,并相应地更新其状态。

Alternatively, you need to look into using a flux pattern (eg using something like Redux). 或者,您需要研究使用磁通量模式(例如,使用Redux之类的东西)。

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

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