1

How can the state/value of a React component change based on an external interaction? For example, if I have a date range component (screenshot below), and I've set dates, but now I want to click a Reset link to clear it, can I?

I can click the 'X', on the component, to clear the dates, but that's all internal component stuff. I have a requirement to clear the dates when hitting the Reset link. I'm not sure how to tell the component, from the outside, that its dates should be reset. How can I do that? I tried passing a variable to the start date property when initially setting up the component, but that variable doesn't get updated based on anything done within the component.

enter image description here

Brandon
  • 38,310
  • 8
  • 82
  • 87
Bob Horn
  • 33,387
  • 34
  • 113
  • 219
  • that's exactly what [Props](https://reactjs.org/docs/components-and-props.html) are for – Guillaume Jul 10 '18 at 17:28
  • We're using our own components that extend React.Component. – Bob Horn Jul 10 '18 at 17:29
  • You can set up a clear method in the child and then use refs to call the child clear method in the parent https://stackoverflow.com/questions/37949981/call-child-method-from-parent – Chase DeAnda Jul 10 '18 at 17:29
  • 3
    A common technique for when two "sibling" components need to interact is to [lift the state up to the first common ancestor](https://reactjs.org/docs/lifting-state-up.html). It that's not an option, it might be worth looking into a state management solution like [MobX](https://github.com/mobxjs/mobx) or [Redux](https://github.com/reduxjs/redux). – Tholle Jul 10 '18 at 17:29
  • In general, if two components need access to the same bit information, that information should be state, and needs to be in the nearest common parent of both components. @Tholle 's comment is probabyl what you're looking for – Guillaume Jul 10 '18 at 17:30
  • Chase: This isn't a parent/child relationship. Tholle: We use redux, but is it appropriate for a reusable component to rely on that? – Bob Horn Jul 10 '18 at 17:32
  • There must be a common ancestor somewhere that both these components are ultimately rendered inside of. That common ancestor should manage the state and be responsible for passing it down as props and also passing down a "reset" function. That common ancestor could just use React state, or it could be a Redux controlled component that is using Redux to hold the state. – Brandon Jul 10 '18 at 17:40
  • @Brandon When you say "passing down a reset function," do you mean a function passed to the date component? If so, what does that date component do with that reset function? The resetting of dates, in this case, is coming from outside the date component. – Bob Horn Jul 10 '18 at 17:46
  • pass "reset" function as a prop to whatever component has the "Reset" button. Pass dates and "change" functions down to the date component so that it can show the currently selected dates and call "change" when the user tries to change the date. – Brandon Jul 10 '18 at 18:40
  • I added an example answer – Brandon Jul 10 '18 at 18:48
  • @BobHorn They should share an equal parent. My answer works for any shared parent. – Chase DeAnda Jul 13 '18 at 19:54

1 Answers1

1

Lift state up is the typical answer. You end up with something like this:

class Parent extends Component {

  // could get this from Redux if you wanted
  state = { dateRange: null };
  // could be a redux action if you wanted
  onDateRangeChange = dateRange => this.setState({ dateRange });
  // could be a redux action if you wanted
  resetDateRange = () => this.onDateRange(null);

  render() {
     const {dateRange} = this.state;

     return (
       <div>
         <SomeComponentThatEventuallyRendersReset onReset={this.resetDateRange} />
         <SomeComponentThatEventuallyRendersDateControl
            onDateRangeChange={this.onDateRangeChange}
            dateRange={dateRange}
         />
       </div>
     );
  }
}

Your Reset control might be something like:

const ResetControl = ({onClick}) => (<button type="button" onClick={onClick}>Reset</button);

Your date picker might be like:

class DatePicker extends Component {

   state = { any transient state you need before "submitting" changes to your parent };

   onSelection = (value) => this.props.onDateRangeChange(value);

   render() {
      return <Whatever onChange={this.onSelection} onValue={this.props.dateRange} />;
   }
}
Brandon
  • 38,310
  • 8
  • 82
  • 87
  • Ok, so basically pass a function to the component so the component can invoke it when the date changes. Thanks. – Bob Horn Aug 03 '18 at 14:47