如何通过反应将数据从对话框发送回父容器?

Posted

技术标签:

【中文标题】如何通过反应将数据从对话框发送回父容器?【英文标题】:How to send data from dialog back to parent container with react? 【发布时间】:2019-10-13 17:01:16 【问题描述】:

我有一个react-big-calendar(父容器),我还有一个选择,日历的事件是根据这个选择(医生姓名)获取的,当我点击它时我有一个按钮,对话框将出现(另一个组件),在此对话框中,我有一个表单可以在选择后添加一个事件,当我发布我的 API 时,我将其保存在本地存储中,但添加的事件不会出现在我的日历上刷新页面并重新选择医生姓名。 但是我想,当我点击保存按钮时,会直接添加到日历上,并且会出现在日历上。

我的日历代码是:

   import Popup from './Popup';
export default class Calendar extends Component 
constructor(props)
    super(props);
    this.state = 
      events : [],
      open: false,

componentDidMount = () => 
    fetch(process.env.REACT_APP_API_BACKEND_YET+'get_liste_praticien.php')
      .then(Response => Response.json())
      .then(data => 
        this.setState ( praticiens : data )
        localStorage.setItem('Liste de praticiens ', JSON.stringify(this.state.praticiens))
    )

fetchData = (nom,identifiant_user) => 
    this.setState(
      events: [],
      evtStorage:[],
      prevEvents:[], 
      evtBackend:[]
    )
      fetch(process.env.REACT_APP_API_BACKEND+'get_liste_planning')
        .then(Response => Response.json())
        .then(data => 
          let evts = data.ListeResult;
          for (let i = 0; i < evts.length; i++) 
            evts[i].start = moment(evts[i].start).toDate();
            evts[i].end = moment(evts[i].end).toDate();
           if(evts[i].typeplanning === '0') this.setState(isConges:true)
            this.state.events.push(evts[i])
                             
          this.setState(
            evtBackend: evts,
            events:  evts
          )
          localStorage.setItem("Liste de planning de " + nom, JSON.stringify(this.state.events));
        ) 
        const evtCached1 = JSON.parse(localStorage.getItem('Liste récente de planning de ' + nom));
        if(evtCached1 !== null) 
          for (let j = 0; j < evtCached1.length; j++) 
            evtCached1[j].start = moment(evtCached1[j].start).toDate();
            evtCached1[j].end = moment(evtCached1[j].end).toDate();
            if(evtCached1[j].typeplanning === '0') this.setState(isConges:true)
            this.state.events.push(evtCached1[j]);
           
          this.setState(
            events:this.state.events,
          );
          localStorage.removeItem("Liste de planning de " + nom);
        
// For the select
handlePraticienChange = id_user => 
    this.setState( 
      openPopupAjout: true,
      id_user: id_user 
    ,() => 
      this.state.praticiens.map((praticien)=> 
          if(this.state.id_user === praticien.id_user)
            this.setState ( nom_user: praticien.nom_user)
           this.fetchData(praticien.nom_user, praticien.identifiant_user);
          
      )
      
    );
  
// for the popup
 ModalAjoutb = (ref) => 
    if (ref) 
      this.ajoutb = ref.handleAjouterb;
     else 
      this.ajoutb = null;
    
  
render() 

    return (
<div>
    <button className="bp3-button bp3-icon-add-to-artifact .bp3-fill" tabIndex="0" onClick=() => this.ajoutb(this.state.id_user, this.state.events)>Add event</button>
    <Select  onChange=this.handlePraticienChange value=this.state.id_user>
        this.state.praticiens.map((praticien) =>
            <Option key=praticien.id_user value=praticien.id_user>praticien.nom_user</Option>
        )
    </Select>
    <DragAndDropCalendar
        selectable
        localizer=localizer
        events=this.state.events 
        views=['month','week','day']
        defaultView="week"
        culture = 'fr'
    />
    <Popup ref=this.ModalAjoutb id_user=this.state.id_user events=this.state.events />
</div>
);


我的对话框代码是:

export default class Popup extends Component 
constructor(props)
    super(props);
    this.state = 
      events : [],

handleAjouterb = (id_user) => 
    this.setState(
      openPopupAjout: true,
      id_user,
    , () => 
        this.fetchingPopup(this.state.id_user, this.state.identifiant_user, this.state.nom_user)
    );
  
fetchingPopup = (id_user, identifiant_user, nom_user) =>
    const praticiensCached = JSON.parse(localStorage.getItem('Liste de praticiens '));
    for (let j = 0; j < praticiensCached.length; j++) 
      if(id_user === praticiensCached[j].id_user)
        identifiant_user = praticiensCached[j].identifiant_user;
        this.setState ( nom_user: praticiensCached[j].nom_user )
    

handleValider = event => 
    event.preventDefault();
    const praticiensCached = JSON.parse(localStorage.getItem('Liste de praticiens '));
    for (let j = 0; j < praticiensCached.length; j++) 
      if(this.state.id_user === praticiensCached[j].id_user)
        this.state.identifiant_user = praticiensCached[j].identifiant_user;
    

      const formData = new FormData();

      formData.append('identifiant_user', this.state.identifiant_user);
      formData.append('heuredebut', this.state.tranchesC[0].startC);
      formData.append('heurefin', this.state.tranchesC[0].endC);
      formData.append('libelleconge', this.state.libelle);
      axios(
        method: 'post',
        url: process.env.REACT_APP_API_BACKEND+'add_event_docteur',
        data: formData,
        headers: 
          'Content-Type': 'application/json',
          'Accept': 'application/json',
        
      )
      .then(() => 
        fetch(process.env.REACT_APP_API_BACKEND+'get_liste_planning/start='+moment().startOf('isoweek').subtract(14,'days').toJSON()+'&end='+moment().endOf('isoweek').add(2,'months').toJSON()+'&identifiant_user='+this.state.identifiant_user)
          .then(Response => Response.json())
          .then(data => 
            let evts = data.ListeResult;
            for (let i = 0; i < evts.length; i++) 
              evts[i].start = moment(evts[i].start).toDate();
              evts[i].end = moment(evts[i].end).toDate();
              this.state.events.push(evts[i])
                               
            this.setState(
              events:  this.state.events
            , ()=> 
              localStorage.setItem('Liste récente de planning de ' + this.state.nom_user, JSON.stringify(this.state.events));
              localStorage.removeItem("Liste de planning de " + this.state.nom_user);
              localStorage.setItem("Liste de planning de " + this.state.nom_user, JSON.stringify(this.state.events));
            )
          )
       )


render() 

    return (
<div>
    <Dialog
        icon="application"
        onClose=this.handleClose
        title="Organisation des plannings du docteur"
        ...this.state
        isOpen=this.state.openPopupAjout>
           <Input id="libelle" style= width: '480px'  value=this.state.libelle onChange=this.handleInputChange('libelle')/>       
            <label className="pt-label .modifier"><strong>Date</strong></label>
            <LocaleProvider locale=fr_FR>
                <RangePicker id="date" name= "date"  locale="fr" placeholder=["Date de début","Date de fin"] separator="-" onChange=this.handleDateCChange
                    value=this.state.dateIC format="DD/MM/YYYY" allowClear=false/> 
            </LocaleProvider>
            <label className="pt-label .modifier"> <strong>Heure de début</strong></label>
            <Time value=el.startC onChange=time => this.handleKeyboardStartCChange(i, time) style=heure disableUnderline=true inputComponent=TextMaskCustom
                    endAdornment= <InputAdornment position="end" style=opacity:'0.4'> <IconButton   onClick=() => this.openDialogC(i, el.startC, "startC")><i  style=fontSize:'18px' className="zmdi zmdi-alarm" /></IconButton>  </InputAdornment>
            />
            <label className="pt-label .modifier"> <strong>Heure de fin</strong></label>
            <Time value=el.endC onChange=time => this.handleKeyboardEndCChange(i, time) style=heure disableUnderline=true inputComponent=TextMaskCustom
                    endAdornment= <InputAdornment position="end" style=opacity:'0.4'> <IconButton  onClick=() => this.openDialogC(i, el.endC, "endC")><i  style=fontSize:'18px' className="zmdi zmdi-alarm" /></IconButton></InputAdornment> />

            <Clock maxWidth="xs" open=this.state.isOpenC onBackdropClick=this.closeDialogC>
            <TimePicker  mode="24h" value=this.createDateFromTextValueC(this.state.datePickerValueC) onChange=this.handleDialogCChange/>
            <DialogActions> <ButtonOk onClick=this.closeDialogC color="primary"> Ok </ButtonOk></DialogActions>
            </Clock>
                <AnchorButton style=display:'inline-block' intent=Intent.SUCCESS onClick=this.handleValider>Valider</AnchorButton>

</div>
);


我想刷新我的事件列表,并在弹出窗口的发布表单之后而不是在刷新页面之后显示我的事件添加到日历中,我将重新选择医生。

我该如何解决?

【问题讨论】:

将 localStorage 添加到 state,然后通过 props 发送 state! @RadonirinaMaminiaina 你能告诉我如何编码吗? 我添加了一个伪代码 @RadonirinaMaminiaina 请检查我的答案 【参考方案1】:

我认为,您可以使用如下代码实现它:

export default ComponentA extends Component 
  // set localStorage to bar state value
  // via click or whatever ...
    foo () 
    this.setState(
      bar: localStorage.getItem('bar')
    )
  

  render () 
    // send the value of state to ComponentB
    return <ComponentB foo=this.state.bar>
  

进入你的组件

export default class ComponentB extends Component 
    render () 
    // display the value of foo prop
    return <div>this.props.foo</div>
  

注意:您始终可以尝试直接从ComponentB 获取您的localStorage 的内容(也许使用ComponentDidUpdate ???),但我向您展示的方式更好。

【讨论】:

我尝试foo (nom) this.setState( events: localStorage.getItem('Liste récente de planning de ' + nom) ),但它不起作用,这是同样的问题。 你怎么称呼你的 foo? 我在 Popup 组件上调用我的 foo,例如:this.state = events: this.props.foo 这样设置状态是一种不好的做法。你应该使用setState ...在你的弹出代码中,只需调用this.foo('your name') 我收到TypeError: _this.props.foo is not a function【参考方案2】:

您是否正在寻找类似的东西

class ComponentB extends React.Component
  render()
    this.props.setInLocalStorage();
    const value = localStorage.getItem("testA");
    return <div>
  This is componentBvalue
  </div>

class ComponentA extends React.Component
 setInLocalStorage = ()=>
   localStorage.setItem('testA', 'Hello');

render()
  return <ComponentB setInLocalStorage=this.setInLocalStorage/>



【讨论】:

但我希望在我从弹出窗口添加事件后,它会直接出现在我的日历上,而不是在刷新页面并重新选择医生后【参考方案3】:

为什么不使用 React 的上下文特性 React Context API

context.js

export const store = 
  something: 'val',
  setSomeThing : () => 
;

export const CalContext = React.createContext(
  store // default value
);

pop-up.js

import CalContext from './context';

class Popup extends React.Component 

   updateValue = () => 
     this.context.setSomeThing('new_value');
       

   render() 
    let calContext = this.context;

    return (
      <button onClick=this.updateValue >
        calContext.something
      </button>
    );
  


Popup.contextType = CalContext;

export default Popup;

calender.js

import CalContext from './context';
import Popup from './pop-up'

class calender extends React.Component 
   constructor(props) 
      this.state = 
         something : 'value'
      
   

  setSomeThing = (newVal) => 
    // actual set something code.
    this.setState(something : newVal);
  

render() 
let contextVal =  something : this.state.something, setSomeThing : this.setSomeThing 
// The entire state is passed to the provider
return (
  <CalContext.Provider value=contextVal>
    <Popup />
  </CalContext.Provider>
   );

【讨论】:

【参考方案4】:

您可以使用 React Context API 或 Redux。

但是,如果您不想要这些,您可以在子组件中使用作为方法的 prop,这样父组件就可以捕获事件。它类似于 Angular 2+ 的输出机制。

这是一个例子:

const ChildComponent = (onSelect = () => ) => 
  return <div onClick=() => onSelect('You selected me')>Child Component</div>


const ParentComponent = () => 
  return <ChildComponent onSelect=message => console.log(message) /> // You selected me

【讨论】:

【参考方案5】:

在您的父组件中,即&lt;Calendar/&gt;,您可以为 say 定义一个方法

HandleNewDataFromPopup(data) 
   this.setState(newData: data)

并将此方法作为道具传递给 Popup 组件

<Popup HandleNewDataFromPopup=this.HandleNewDataFromPopup/>

在您的&lt;Popup/&gt; 组件中,在获取调用成功的方法handleValider 中,您可以调用方法HandleNewDataFromPopup (this.props.HandleNewDataFromPopup) 来填充父组件中的数据

handleValider() 
  // on axios success
  this.props.HandleNewDataFromPopup(data)

这能回答你的问题吗?

【讨论】:

【参考方案6】:

不要在你的 state 中保存事件,在 Popup 中直接从 props 访问事件。

在您的日历中,创建一个将更新状态的函数。

updateEvents = (events, callback = () => ) => 
  this.setState(
    
      events
    ,
    callback
  );
;

<Popup updateEvents=this.updateEvents ref=this.ModalAjoutb id_user=this.state.id_user events=this.state.events />

弹出窗口

export default class Popup extends Component 
  constructor(props) 
    super(props);
  

  handleAjouterb = id_user => 
    this.setState(
      
        openPopupAjout: true,
        id_user
      ,
      () => 
        this.fetchingPopup(
          this.state.id_user,
          this.state.identifiant_user,
          this.state.nom_user
        );
      
    );
  ;
  fetchingPopup = (id_user, identifiant_user, nom_user) => 
    const praticiensCached = JSON.parse(
      localStorage.getItem('Liste de praticiens ')
    );
    for (let j = 0; j < praticiensCached.length; j++) 
      if (id_user === praticiensCached[j].id_user) 
        identifiant_user = praticiensCached[j].identifiant_user;
        this.setState( nom_user: praticiensCached[j].nom_user );
      
    
    handleValider = event => 
      event.preventDefault();
      const praticiensCached = JSON.parse(
        localStorage.getItem('Liste de praticiens ')
      );
      for (let j = 0; j < praticiensCached.length; j++) 
        if (this.state.id_user === praticiensCached[j].id_user)
          this.state.identifiant_user = praticiensCached[j].identifiant_user;
      

      const formData = new FormData();

      formData.append('identifiant_user', this.state.identifiant_user);
      formData.append('heuredebut', this.state.tranchesC[0].startC);
      formData.append('heurefin', this.state.tranchesC[0].endC);
      formData.append('libelleconge', this.state.libelle);
      axios(
        method: 'post',
        url: process.env.REACT_APP_API_BACKEND + 'add_event_docteur',
        data: formData,
        headers: 
          'Content-Type': 'application/json',
          Accept: 'application/json'
        
      ).then(() => 
        fetch(
          process.env.REACT_APP_API_BACKEND +
            'get_liste_planning/start=' +
            moment()
              .startOf('isoweek')
              .subtract(14, 'days')
              .toJSON() +
            '&end=' +
            moment()
              .endOf('isoweek')
              .add(2, 'months')
              .toJSON() +
            '&identifiant_user=' +
            this.state.identifiant_user
        )
          .then(Response => Response.json())
          .then(data => 
            let evts = data.ListeResult;
            for (let i = 0; i < evts.length; i++) 
              evts[i].start = moment(evts[i].start).toDate();
              evts[i].end = moment(evts[i].end).toDate();
            
            this.props.updateEvents(evts, () => 
              localStorage.setItem(
                'Liste récente de planning de ' + this.state.nom_user,
                JSON.stringify(evts)
              );
              localStorage.removeItem(
                'Liste de planning de ' + this.state.nom_user
              );
              localStorage.setItem(
                'Liste de planning de ' + this.state.nom_user,
                JSON.stringify(evts)
              );
            );
          );
      );
    ;
  ;

  render() 
    return (
      <div>
        <Dialog
          icon="application"
          onClose=this.handleClose
          title="Organisation des plannings du docteur"
          ...this.state
          isOpen=this.state.openPopupAjout
        >
          <Input
            id="libelle"
            style= width: '480px' 
            value=this.state.libelle
            onChange=this.handleInputChange('libelle')
          />
          <label className="pt-label .modifier">
            <strong>Date</strong>
          </label>
          <LocaleProvider locale=fr_FR>
            <RangePicker
              id="date"
              name="date"
              locale="fr"
              placeholder=['Date de début', 'Date de fin']
              separator="-"
              onChange=this.handleDateCChange
              value=this.state.dateIC
              format="DD/MM/YYYY"
              allowClear=false
            />
          </LocaleProvider>
          <label className="pt-label .modifier">
            ' '
            <strong>Heure de début</strong>
          </label>
          <Time
            value=el.startC
            onChange=time => this.handleKeyboardStartCChange(i, time)
            style=heure
            disableUnderline=true
            inputComponent=TextMaskCustom
            endAdornment=
              <InputAdornment position="end" style= opacity: '0.4' >
                ' '
                <IconButton
                  onClick=() => this.openDialogC(i, el.startC, 'startC')
                >
                  <i style= fontSize: '18px'  className="zmdi zmdi-alarm" />
                </IconButton>' '
              </InputAdornment>
            
          />
          <label className="pt-label .modifier">
            ' '
            <strong>Heure de fin</strong>
          </label>
          <Time
            value=el.endC
            onChange=time => this.handleKeyboardEndCChange(i, time)
            style=heure
            disableUnderline=true
            inputComponent=TextMaskCustom
            endAdornment=
              <InputAdornment position="end" style= opacity: '0.4' >
                ' '
                <IconButton
                  onClick=() => this.openDialogC(i, el.endC, 'endC')
                >
                  <i style= fontSize: '18px'  className="zmdi zmdi-alarm" />
                </IconButton>
              </InputAdornment>
            
          />
          <Clock
            maxWidth="xs"
            open=this.state.isOpenC
            onBackdropClick=this.closeDialogC
          >
            <TimePicker
              mode="24h"
              value=this.createDateFromTextValueC(this.state.datePickerValueC)
              onChange=this.handleDialogCChange
            />
            <DialogActions>
              ' '
              <ButtonOk onClick=this.closeDialogC color="primary">
                ' '
                Ok' '
              </ButtonOk>
            </DialogActions>
          </Clock>
          <AnchorButton
            style= display: 'inline-block' 
            intent=Intent.SUCCESS
            onClick=this.handleValider
          >
            Valider
          </AnchorButton>
      </div>
    );
  

【讨论】:

以上是关于如何通过反应将数据从对话框发送回父容器?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过ajax fetch api响应将从laravel控制器接收到的数据发送到另一个页面

如何通过本机反应将新字段数据更新到现有文档而不覆盖firebase-9中的现有数据

Fancybox (jQuery) - 将信息从父级传递到 iframe 并将 iframe 传递回父级

如何使用本机反应将文档添加到firestore数据库

无法将子进程发送回父进程的消息

反应将 onClick 值从一个类传递到另一个类