У меня есть реагировать-большой-календарь (родительский контейнер), у меня также есть выбор, события календаря извлекаются в соответствии с этим выбором (имя врача), и у меня есть кнопка, когда я нажимаю на нее, появляется диалоговое окно (другое компонент), в этом диалоговом окне у меня есть форма для добавления события после выбора, когда я публикую свой 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>
);
}}
Я хочу обновить список своих событий и добавить мое событие в календарь после публикации формы во всплывающем окне, а не после обновления страницы, и я повторно выберу врача.
Как я могу это исправить?
@RadonirinaMaminiaina Можете ли вы дать мне, как это закодировать, пожалуйста?
Я добавил псевдокод
@RadonirinaMaminiaina проверьте мой ответ, пожалуйста
Я думаю, вы можете добиться этого, используя такой код:
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) })}
, но это не работает, это та же проблема.
а как вы называете свой foo?
Я вызываю свой foo во всплывающем компоненте, например: this.state = { events: this.props.foo }
Это плохая практика - устанавливать состояние таким образом. вы должны использовать setState
... В вашем всплывающем коде просто вызовите this.foo('your name')
Я получаю TypeError: _this.props.foo is not a function
это не this.props.foo()
а только this.foo()
Он должен добавить его после ответа axios на компонент Popup?
Я пытаюсь ComponentDidUpdate
, но проблема все та же.
Вы ищете что-то вроде этого
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}/>
}
}
но я хочу, чтобы после добавления события из всплывающего окна оно отображалось в моем календаре напрямую, а не после обновления страницы и повторного выбора врача
Почему бы вам не использовать контекстную функцию React Контекстный API реакции
export const store = {
something: 'val',
setSomeThing : () => {}
};
export const CalContext = React.createContext(
store // default value
);
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;
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>
);
}
}
Добавьте localStorage в состояние, а затем отправьте состояние через реквизит!