Reputation: 31
I created two react classes. One of this - child class name - ChildView, bind data into dropdown office fabric component and I use on ParentView class
ChildView, code:
export class ChildView extends React.Component<any, IChildView >{
constructor(props) {
super(props)
this.state = {
selectedKey: "1",
selectedText: "one - 1",
items: this._getItems()
}
}
componentDidMount() {
console.log('component did mount');
}
private _getItems() {
return [
{ key: '1', text: 'one - 1' },
{ key: '2', text: 'two - 2' },
{ key: '3', text: 'three - 3' },
{ key: '4', text: 'four - 4' },
{ key: '5', text: 'five - 5' },
{ key: '6', text: 'six - 6' },
{ key: '7', text: 'seven - 7' },
{ key: '8', text: 'eight - 8' },
{ key: '9', text: 'nine - 9' },
{ key: '10', text: 'ten - 10' },
]
}
public render() {
return (<Dropdown defaultSelectedKey={this.state.selectedKey}
options={this.state.items} />);
}
}
ParentView, code:
export default class ParentView extends React.Component<any, IParentView> {
constructor(props) {
super(props);
}
public render(): React.ReactElement<IParentViewProps> {
return (<ChildView />);}}
My question:
1) How I can return from ChildView selectedKey in ParentView class.?. I read in documentation, there is 'componentRef'. So I update my code in ParentView:
public render(): React.ReactElement<IParentViewProps> {
return (<ChildView componentRef={(ddItems)=>this.something = ddItems}/>);}}
and I don't know what next.
Upvotes: 2
Views: 7332
Reputation: 2519
React isn't really built around parents asking their children for things. Instead it is built around parents telling their children things and children telling their parents things. Thus instead of asking on demand, you should be having the parent monitoring or controlling the child so that the parent always knows what the child has selected - then it would not need to get it on demand. Here is an example of how you can do this:
import { IDropdownOption } from 'office-ui-fabric-react';
import * as React from 'react';
import { ExampleDropdown } from './ExampleDropdown';
interface State {
exampleDropdown?: IDropdownOption;
}
export class Parent extends React.Component<any, State> {
state = { } as State;
onDropdownChange = (keyValue?: IDropdownOption) => {
if (keyValue && keyValue.key) {
this.setState({ exampleDropdown: keyValue })
}
}
render() {
return <ChildView
onSelectionChange={this.onDropdownChange}
selected={this.state.exampleDropdown}
/>
}
}
import { Dropdown as OfficeFabricDropdown, IDropdownOption } from 'office-ui-fabric-react';
import * as React from 'react';
interface Props {
/** Provide this value to control the state. If left blank it will manage its own state */
selected?: IDropdownOption,
onSelectionChange?: (keyValue?: IDropdownOption) => void,
}
interface State {
currentState?: IDropdownOption,
items: IDropdownOption[],
selectedIndex?: number,
}
export class ChildView extends React.Component<Props, State> {
state: State = {
items: [
{ key: '1', text: 'one - 1' },
{ key: '2', text: 'two - 2' },
{ key: '3', text: 'three - 3' },
{ key: '4', text: 'four - 4' },
{ key: '5', text: 'five - 5' },
{ key: '6', text: 'six - 6' },
{ key: '7', text: 'seven - 7' },
{ key: '8', text: 'eight - 8' },
{ key: '9', text: 'nine - 9' },
{ key: '10', text: 'ten - 10' },
],
} as State;
onDropdownChange = (event: React.FormEvent<HTMLDivElement> | any, option: any = {}, index?: number) => {
this.setState({
currentState: index || index === 0 ? this.state.items[index] : undefined,
selectedIndex: index,
});
const currentSelected = (index || index === 0) ? this.state.items[index] : undefined;
this.props.onSelectionChange && this.props.onSelectionChange(currentSelected);
};
render(): JSX.Element {
const selected = this.props.selected && this.props.selected.key ||
this.state.currentState && this.state.currentState.key;
return <OfficeFabricDropdown
{...this.props}
ariaLabel="Example Dropdown"
label="Example Dropdown"
options={this.state.items}
placeHolder={"Pick a number"}
selectedKey={selected}
onChange={this.onDropdownChange}
/>;
}
}
export default ChildView;
Having the parent control the state has some nice advantages, such as being able to save and restore state so that when a user leaves the page and comes back the state is as they left it. However, if you don't want that, you can simply remove the selected={this.state.exampleDropdown}
line and everything will still work and you will still have the state in the parent.
Now, all that being said, the double pointer to "ask" trick in the other answer is wonderful when the occasion demands it, but it should be used sparingly and doesn't seem a good solution for this problem.
Upvotes: 1
Reputation: 40
You can pass a function to the Child from the Parent which will be called when changing the selected key in the Child:
export class ChildView extends React.Component<any, IChildView >{
constructor(props) {
super(props)
this.state = {
selectedKey: "1",
selectedText: "one - 1",
items: this._getItems()
}
this.keyChanged = this.keyChanged.bind(this);
}
private _getItems() {
return [...]
}
keyChanged(option){
this.props.updateKey(option.key);
}
public render() {
return (<Dropdown defaultSelectedKey={this.state.selectedKey}
options={this.state.items}
onChanged={this.keyChanged} />);
}
}
And Parent render method:
public render(): React.ReactElement<IParentViewProps> {
return (<ChildView updateKey={this.setKey} />);
}
And define setKey function to accept the key in the parent.
Upvotes: 1