Skip to content

Commit

Permalink
Added docs
Browse files Browse the repository at this point in the history
  • Loading branch information
mweststrate committed Jul 9, 2023
1 parent 36eeb2f commit ef6a062
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 10 deletions.
13 changes: 8 additions & 5 deletions .changeset/flat-pumas-cross.md
Expand Up @@ -2,8 +2,11 @@
"mobx-react-lite": patch
---

fix #3671: `observer` + `StrictMode`
BC: Class component's `props`/`state`/`context` are no longer observable. Attempt to use these in any derivation other than component's `render` throws and error.
BC: Attempt to apply `observer` on a component that is already an `observer` throws instead of warning.
docs: link for mobx-react docs
docs: extending `observer` class components is not supported
- Fixed `observer` in `StrictMode` #3671

---

## "mobx-react": major

- Class component's `props`/`state`/`context` are no longer observable. Attempt to use these in any derivation other than component's `render` throws and error.
- Extending or applying `observer` classes is now explicitly forbidden
93 changes: 88 additions & 5 deletions packages/mobx-react/README.md
Expand Up @@ -15,10 +15,11 @@ This package supports both React and React Native.

Only the latest version is actively maintained. If you're missing a fix or a feature in older version, consider upgrading or using [patch-package](https://www.npmjs.com/package/patch-package)

| NPM Version | Support MobX version | Supported React versions | Supports hook based components |
| NPM Version | Support MobX version | Supported React versions | Added support for: |
| ----------- | -------------------- | ------------------------ | -------------------------------------------------------------------------------- |
| v7 | 6.\* | >16.8 | Yes |
| v6 | 4.\* / 5.\* | >16.8 <18 | Yes |
| v8 | 6.\* | >16.8 | Hooks, React 18.2 in strict mode |
| v7 | 6.\* | >16.8 < 18.2 | Hooks |
| v6 | 4.\* / 5.\* | >16.8 <18 | Hooks |
| v5 | 4.\* / 5.\* | >0.13 <18 | No, but it is possible to use `<Observer>` sections inside hook based components |

mobx-react 6 / 7 is a repackage of the smaller [mobx-react-lite](https://github.com/mobxjs/mobx/tree/main/packages/mobx-react-lite) package + following features from the `mobx-react@5` package added:
Expand Down Expand Up @@ -57,8 +58,6 @@ Function (and decorator) that converts a React component definition, React compo

#### Class Components

When using component classes, `this.props` and `this.state` will be made observables, so the component will react to all changes in props and state that are used by `render`.

`shouldComponentUpdate` is not supported. As such, it is recommended that class components extend `React.PureComponent`. The `observer` will automatically patch non-pure class components with an internal implementation of `React.PureComponent` if necessary.

Extending `observer` class components is not supported. Always apply `observer` only on the last class in the inheritance chain.
Expand Down Expand Up @@ -89,6 +88,90 @@ class TodoView extends React.Component {
const TodoView = observer(({ todo }) => <div>{todo.title}</div>)
```

##### Note on using props and state in derivations

`mobx-react` version 6 and lower would automatically turn `this.state` and `this.props` into observables.
This has the benefit that computed properties and reactions were able to observe those.
However, since this pattern is fundamentally incompatible with `StrictMode` in React 18.2 and higher, this behavior has been removed in React 18.

As a result, we recommend to no longer mark properties as `@computed` in observer components if they depend on `this.state` or `this.props`.

```javascript
@observer
class Doubler extends React.Component<{ counter: number }> {
@computed // BROKEN! <-- @computed should be removed in mobx-react > 7
get doubleValue() {
// Changes to this.props will no longer be detected properly, to fix it,
// remove the @computed annotation.
return this.props * 2
}

render() {
return <div>{this.doubleValue}</div>
}
}
```

Similarly, reactions will no longer respond to `this.state` / `this.props`. This can be overcome by creating an observable copy:

```javascript
@observer
class Alerter extends React.Component<{ counter: number }> {
@observable observableCounter: number
reactionDisposer

constructor(props) {
this.observableCounter = counter

// set up a reaction, by observing the observable,
// rather than the prop which is non-reactive:
this.reactionDisposer = autorun(() => {
if (this.observableCounter > 10) {
alert("Reached 10!")
}
})
}

componentDidUpdate() {
// sync the observable from props
this.observableCounter = this.props.counter
}

render() {
return <div>{this.props.counter}</div>
}

componentWillUnmount() {
this.reactionDisposer()
}
}
```

MobX-react will try to detect cases where `this.props`, `this.state` or `this.context` are used by any other derivation than the `render` method of the owning component and throw.
This is to make sure that neither computed properties, nor reactions, nor other components accidentally rely on those fields to be reactive.

This includes cases where a render callback is passed to a child, that will read from the props or state of a parent component.
As a result, passing a function that might later read a property of a parent in a reactive context will throw as well.
Instead, when using a callback function that is being passed to an `observer` based child, the capture should be captured locally first:

```javascript
@observer
class ChildWrapper extends React.Component<{ counter: number }> {
render() {
// Collapsible is an observer component that should respond to this.counter,
// if it is expanded

// BAD:
return <Collapsible onRenderContent={() => <h1>{this.props.counter}</h1>} />

// GOOD: (causes to pass down a fresh callback whenever counter changes,
// that doesn't depend on its parents props)
const counter = this.props.counter
return <Collapsible onRenderContent={() => <h1>{counter}</h1>} />
}
}
```

### `Observer`

`Observer` is a React component, which applies `observer` to an anonymous region in your component.
Expand Down

0 comments on commit ef6a062

Please sign in to comment.