如何通过反应将数据从对话框发送回父容器?
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】:在您的父组件中,即<Calendar/>
,您可以为 say 定义一个方法
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)
这能回答你的问题吗?
【讨论】:
【参考方案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中的现有数据