Skip to content

alexkrolick/react-remount-component

Repository files navigation

react-remount-component

The Problem

You want a React component to reset state when certain props change. Without this library you can do this:

  • Class components: implement getDerivedStateFromProps and componentDidUpdate to track and respond to props changes
  • Function components: use a state hook with a cache of previous props to manually call the set function of related state hooks
  • Either: rely on consumers to pass a key. This can't be enforced and removes control over internal state from the library.

This Solution

react-remount-component is a higher-order component that takes a comparison function for new props and previous props. Returning true from the comparison remounts the component.

Currently, the HOC generates a random key for the wrapped component when a reset is requested. This is an implementation detail that may change in the future.

Usage

See usage.test.js

Class Component

class UserCard extends React.Component {
  state = {
    expanded: false,
  };

  render() {
    const { user } = this.props;
    return (
      <div className="user-card">
        <Name name={user.name} />
        <button onClick={() => this.setState({ expanded: true })}>
          Details
        </button>
        {this.state.expanded && (
          <React.Fragment>
            <Date date={user.birthdate} />
            <Avatar user={user} />
          </React.Fragment>
        )}
      </div>
    );
  }
}

export default withRemount(UserCard, (props, prevProps) => {
  const prevUserId = prevProps.user && prevProps.user.id;
  const nextUserId = props.user && props.user.id;

  if (nextUserId !== prevUserId) {
    return true; // remount!
  }

  return false; // don't remount otherwise
});

Function Component

function UserCard(props) {
  const { user } = props;
  const [isExpanded, setExpanded] = React.useState(false);
  return (
    <div className="user-card">
      <div>Name: {user.name}</div>
      <div>
        <button onClick={() => setExpanded({ expanded: true })}>
          See Details
        </button>
      </div>
      {isExpanded && (
        <React.Fragment>
          <div>Birthday: {user.birthDate}</div>
          <div>Favorite Color: {user.favoriteColor}</div>
        </React.Fragment>
      )}
    </div>
  );
}

export default withRemount(UserCard, (props, prevProps) => {
  const prevUserId = prevProps.user && prevProps.user.id;
  const nextUserId = props.user && props.user.id;

  if (nextUserId !== prevUserId) {
    return true; // remount!
  }

  return false; // don't remount otherwise
});

React RFC

reactjs/rfcs#62

License

MIT

Contributing

Code of Conduct

About

Reset React component state when props change

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published