Search code examples
reactjsmaterial-uireact-component

how to call child component's method from parent component's event in Reactjs


Hi I am trying to call the method from parent component to child.

I have researched lot i didn't get any good solution with child(functional component). if there is a solution can any explain me to solve this.

APP.js

     import React from 'react';
        import IntegrationDownshift from './members'
        class App extends React.Component {
             constructor(props) {
              super(props);
              this.state = {
                 Name: "Name from state...",
                 Description: "Description from state...",
                Data:[data]
              }
           }
           Clear(){
    this.IntegrationDownshift.ClearRecord();     // Here I'm trying to call the method on such event  

 }
          render() {  
             return (
                <div>
         <IntegrationDownshift Members={this.state.Data}/>
          <Button variant="contained" color="secondary"  onClick={this.Clear.bind(this)} >  // when i click the button it will trigger
        clear         // when i click the button it will trigger
      </Button>
               </div>
             );
          }
        }

    export default App;`

members

    var suggestions = []
    var members=[];
    function renderInput(inputProps) {
      const { InputProps, classes, ref, ...other } = inputProps;
      return (
        <TextField
          InputProps={{
            inputRef: ref,
            classes: {
              root: classes.inputRoot,
              input: classes.inputInput,
            },
            ...InputProps,
          }}
          {...other}
        />
      );
    }
    function renderSuggestion(suggestionProps) {
      const { suggestion, index, itemProps, highlightedIndex, selectedItem } = suggestionProps;
      const isHighlighted = highlightedIndex === index;
      const isSelected = (selectedItem || '').indexOf(suggestion.label) > -1;
      return (
        <MenuItem
          {...itemProps}
          key={suggestion.label}
          selected={isHighlighted}
          component="div"
          style={{
            fontWeight: isSelected ? 500 : 400,
          }}
        >
          {suggestion.label}
        </MenuItem>
      );
    }
    renderSuggestion.propTypes = {
      highlightedIndex: PropTypes.number,
      index: PropTypes.number,
      itemProps: PropTypes.object,
      selectedItem: PropTypes.string,
      suggestion: PropTypes.shape({ label: PropTypes.string }).isRequired,
    };
    function getSuggestions(value, { showEmpty = false } = {}) {
      const inputValue = deburr(value.trim()).toLowerCase();
      const inputLength = inputValue.length;
      let count = 0;
      return inputLength === 0 && !showEmpty
        ? []
        : suggestions.filter(suggestion => {
            const keep =
              count < 5 && suggestion.label.slice(0, inputLength).toLowerCase() === inputValue;
            if (keep) {
              count += 1;
            }
            return keep;
          });
    }
    function DownshiftMultiple(props) {
        suggestions=props.Members;
      const { classes } = props;
      const [inputValue, setInputValue] = React.useState('');
      const [selectedItem, setSelectedItem] = React.useState([]);
      function handleKeyDown(event) {
        if (selectedItem.length && !inputValue.length && event.key === 'Backspace') {
          setSelectedItem(selectedItem.slice(0, selectedItem.length - 1));
        }
      }
       function ClearRecord(){     // ** trying to call this function **
       setSelectedItem(selectedItem.slice(0, selectedItem.length - selectedItem.length));
  }

      function handleInputChange(event) {
        setInputValue(event.target.value);
      }
      function handleChange(item) {
        let newSelectedItem = [...selectedItem];
        if (newSelectedItem.indexOf(item) === -1) {
          newSelectedItem = [...newSelectedItem, item];
          members=newSelectedItem;   // **want to send this**
           props.onDataChanged(members)// **here i'm trying to send the value**
        }
        setInputValue('');
        setSelectedItem(newSelectedItem);
      }    
      const handleDelete = item => () => {
        const newSelectedItem = [...selectedItem];
        newSelectedItem.splice(newSelectedItem.indexOf(item), 1);
        setSelectedItem(newSelectedItem);
      };    
      return (
        <Downshift
          id="downshift-multiple"
          inputValue={inputValue}
          onChange={handleChange}
          selectedItem={selectedItem}
        >
          {({
            getInputProps,
            getItemProps,
            getLabelProps,
            isOpen,
            inputValue: inputValue2,
            selectedItem: selectedItem2,
            highlightedIndex,
          }) => {
            const { onBlur, onChange, onFocus, ...inputProps } = getInputProps({
              onKeyDown: handleKeyDown,
              placeholder: 'Select multiple Members',
            });

            return (
              <div className={classes.container}>
                {renderInput({
                  fullWidth: true,
                  classes,
                  InputLabelProps: getLabelProps(),
                  InputProps: {
                    startAdornment: selectedItem.map(item => (
                      <Chip
                        key={item}
                        tabIndex={-1}
                        label={item}
                        className={classes.chip}
                        onDelete={handleDelete(item)}
                      />
                    )),
                    onBlur,
                    onChange: event => {
                      handleInputChange(event);
                      onChange(event);
                    },
                    onFocus,
                  },
                  inputProps,
                })}

                {isOpen ? (
                  <Paper className={classes.paper} square>
                    {getSuggestions(inputValue2).map((suggestion, index) =>
                      renderSuggestion({
                        suggestion,
                        index,
                        itemProps: getItemProps({ item: suggestion.label }),
                        highlightedIndex,
                        selectedItem: selectedItem2,
                      }),
                    )}
                  </Paper>
                ) : null}
              </div>
            );
          }}
        </Downshift>
      );
    }

    DownshiftMultiple.propTypes = {
      classes: PropTypes.object.isRequired,
    };

    const useStyles = makeStyles(theme => ({
      root: {
        flexGrow: 1,
        height: 250,
      },
      container: {
        flexGrow: 1,
        position: 'relative',
      },
      paper: {
        position: 'absolute',
        zIndex: 1,
        marginTop: theme.spacing(1),
        left: 0,
        right: 0,
      },
      chip: {
        margin: theme.spacing(0.5, 0.25),
      },
      inputRoot: {
        flexWrap: 'wrap',
      },
      inputInput: {
        width: 'auto',
        flexGrow: 1,
      },
      divider: {
        height: theme.spacing(2),
      },
    }));

    let popperNode;

    export default function IntegrationDownshift(props) {
        debugger
      const classes = useStyles();
      const Members=props.Members;
       props.onDataChanged("test")

      return (
        <div className={classes.root}>

          <DownshiftMultiple classes={classes} Members={Members}  />

        </div>
      );
    }

I'm trying to implement this https://codesandbox.io/s/runh6 functionality which is material UI. I'm not able to call the method from parent to child. in this operation i'm trying to clear the records in app.js click event. Is there a way to clear the data in app.js.


Solution

  • In fact, these parent and child components structure does not fit into the react idea. ReactJS only recommends one-way processing from parent to child. But do not worry.

    You can solve this by using the state value in the parent and the method of passing the parent's function to the child using props.

    App.js

    this.state = {
       Name: "Name from state...",
       Description: "Description from state...",
       Data:[data],
       resetFlag: false,
    }
    ...
    setReset = () => {
       this.setState(prevState => ({ resetFlag: !prevState.resetFlag }));
    };
    ...
    // this.IntegrationDownshift.ClearRecord(); you can't call children's function directly
    if(!this.state.resetFlag) {
       this.setReset();
    }
    ...
    // then pass state value and function to child.
    <IntegrationDownshift Members={this.state.Data} resetFlag={this.state.resetFlag} setReset={this.setReset}/>
    
    

    Members

    function DownshiftMultiple(props) {
    ...
       // hook props changes
       React.useEffect(() => {
         // component updated
         if(props.resetFlag) {
            // This is the place where you can clear your data
            ClearRecord();
            // set resetFlag as false to prevent erasing your data again.
            props.setReset();
         } 
       });