Как отправить данные из диалога обратно в родительский контейнер с помощью реакции?

У меня есть реагировать-большой-календарь (родительский контейнер), у меня также есть выбор, события календаря извлекаются в соответствии с этим выбором (имя врача), и у меня есть кнопка, когда я нажимаю на нее, появляется диалоговое окно (другое компонент), в этом диалоговом окне у меня есть форма для добавления события после выбора, когда я публикую свой 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 в состояние, а затем отправьте состояние через реквизит!

Radonirina Maminiaina 28.05.2019 10:02

@RadonirinaMaminiaina Можете ли вы дать мне, как это закодировать, пожалуйста?

Ichrak Mansour 28.05.2019 10:03

Я добавил псевдокод

Radonirina Maminiaina 28.05.2019 10:23

@RadonirinaMaminiaina проверьте мой ответ, пожалуйста

Ichrak Mansour 28.05.2019 11:30
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
5
4
4 731
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Я думаю, вы можете добиться этого, используя такой код:

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>
  }
}

Примечание: Вы всегда можете попытаться получить содержимое вашего localStorageнепосредственно из ComponentB(может быть, используя ComponentDidUpdate???), но способ, который я вам покажу, лучше.

Я пытаюсь foo (nom) { this.setState({ events: localStorage.getItem('Liste récente de planning de ' + nom) })}, но это не работает, это та же проблема.

Ichrak Mansour 28.05.2019 11:28

а как вы называете свой foo?

Radonirina Maminiaina 28.05.2019 11:30

Я вызываю свой foo во всплывающем компоненте, например: this.state = { events: this.props.foo }

Ichrak Mansour 28.05.2019 11:32

Это плохая практика - устанавливать состояние таким образом. вы должны использовать setState ... В вашем всплывающем коде просто вызовите this.foo('your name')

Radonirina Maminiaina 28.05.2019 11:47

Я получаю TypeError: _this.props.foo is not a function

Ichrak Mansour 28.05.2019 12:41

это не this.props.foo() а только this.foo()

Radonirina Maminiaina 28.05.2019 12:42

Он должен добавить его после ответа axios на компонент Popup?

Ichrak Mansour 28.05.2019 12:57

Я пытаюсь ComponentDidUpdate, но проблема все та же.

Ichrak Mansour 31.05.2019 09:03

Вы ищете что-то вроде этого

class ComponentB extends React.Component{
  render(){
    this.props.setInLocalStorage();
    const value = localStorage.getItem("testA");
    return <div>
  This is componentB{value}
  </div>}
}
class ComponentA extends React.Component{
 setInLocalStorage = ()=>{
   localStorage.setItem('testA', 'Hello');
}
render(){
  return <ComponentB setInLocalStorage = {this.setInLocalStorage}/>
}
}

но я хочу, чтобы после добавления события из всплывающего окна оно отображалось в моем календаре напрямую, а не после обновления страницы и повторного выбора врача

Ichrak Mansour 29.05.2019 14:31

Почему бы вам не использовать контекстную функцию React Контекстный API реакции

контекст.js

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

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

всплывающее окно.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;

календарь.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>
   );}
}

Вы можете использовать React Context API или Redux.

Но если вам это не нужно, вы можете использовать реквизит, который является методом в вашем дочернем компоненте, чтобы родитель мог зафиксировать событие. Это похоже на механику вывода из Angular 2+.

Вот пример:

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

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

В вашем родительском компоненте, т.е. <Calendar/>, вы можете определить метод, например

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

и передайте этот метод как реквизит в компоненте Popup

<Popup HandleNewDataFromPopup = {this.HandleNewDataFromPopup}/>

и в вашем компоненте <Popup/> в методе handleValider при успешном вызове выборки вы можете вызвать метод HandleNewDataFromPopup (this.props.HandleNewDataFromPopup) для заполнения данных в вашем родительском компоненте

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

Отвечает ли это на ваш вопрос?

Ответ принят как подходящий

Не сохраняйте события в своем состоянии, во всплывающем окне доступ к событиям напрямую из реквизита.

В своем календаре создайте функцию, которая будет обновлять состояние.

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>
    );
  }
}

Другие вопросы по теме