2016-10-21 5 views
0

Это мой компонент-структура: ExchangeRateInput ExhangeRateValueInput ExhangeRateDialogРеакция. SetState не обновляет состояние субкомпонентам

состояние открытым в передается через ExhangeRateDialog в качестве опоры. Но когда i setState открыт для правды в ExchangeRateInput он, кажется, не меняется в 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; 
+0

В вашем компоненте 'ExchangeRateValueInput' вы, кажется, передаете анонимную функцию в' setState() '. Почему бы вам просто не вызвать 'this.props.onChange (returnValue)' до или после вашего 'this.setState()' –

+0

Это правильно. Вид ненужный. Но это не должно иметь ничего общего с проблемой, или я ошибаюсь? – filemilk

+0

Nvm. Не понял, что второй параметр для setState - это функция обратного вызова. Игнорируйте мой предыдущий комментарий. –

ответ

1

Вы проходите value от ExchangeRateInput до ExchangeRateValueInput, но затем вы храните его во внутреннем состоянии ExchangeRateValueInput. На данный момент он полностью отключен от ExchangeRateInput. Итак, когда ExchangeRateValueInput обновляет свое состояние, его родитель ничего не знает об этом.

Вы можете переписать так, чтобы все состояние управлялось в корневом компоненте (ExchangeRateInput), и оно передает это состояние детям, которые ссылаются только на реквизиты, а не на собственное внутреннее состояние. Затем, когда детям необходимо обновить состояние, они могут вызывать определенное событие (например, this.props.onChange или что-то еще). ExchangeRateInput будет обрабатывать эти события и соответствующим образом обновлять его состояние.

В качестве альтернативы вам необходимо изучить шаблон потока (например, используя что-то вроде Redux).

+0

Это имеет смысл. Быстрое изменение, и это сработало. Большое спасибо! Я пытаюсь избежать flux/redux для этого проекта. – filemilk

 Смежные вопросы

  • Нет связанных вопросов^_^