-
-
Notifications
You must be signed in to change notification settings - Fork 350
Add Observer render and inject sugar #387 #403
Changes from 6 commits
9a92db4
1edd04a
1c54100
13b416d
827a054
fac7e87
f8c2cfb
484aec2
d4596da
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -83,8 +83,6 @@ The rendering in the function will be tracked and automatically re-rendered when | |
This can come in handy when needing to pass render function to external components (for example the React Native listview), or if you | ||
dislike the `observer` decorator / function. | ||
|
||
Example: | ||
|
||
```javascript | ||
class App extends React.Component { | ||
render() { | ||
|
@@ -105,6 +103,56 @@ React.render(<App person={person} />, document.body) | |
person.name = "Mike" // will cause the Observer region to re-render | ||
``` | ||
|
||
In case you are a fan of render props, you can use that instead of children. Be advised, that you cannot use both approaches at once, children have a precedence. | ||
|
||
Here goes example showing render prop only | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This line is a bogus one, I did not mean to include it by using italic text :) |
||
|
||
```javascript | ||
class App extends React.Component { | ||
render() { | ||
return ( | ||
<div> | ||
{this.props.person.name} | ||
<Observer | ||
render={(props) => <div>{props.person.name}</div>} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch, this is an oversight. It should refer to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry ,a stupid fault zzzzzz should refer to this.props |
||
/> | ||
</div> | ||
) | ||
} | ||
} | ||
|
||
const person = observable({ name: "John" }) | ||
|
||
React.render(<App person={person} />, document.body) | ||
person.name = "Mike" // will cause the Observer region to re-render | ||
``` | ||
|
||
Observer can also inject the stores simply by passing a selector function. | ||
|
||
Example with inject | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same for this line, it's redundant imo. |
||
|
||
```javascript | ||
|
||
const NameDisplayer = ({ name }) => <h1>{name}</h1> | ||
|
||
const user = mobx.observable({ | ||
name: "Noa" | ||
}) | ||
|
||
const UserNameDisplayer = ()=>( | ||
<Observer | ||
inject={(stores)=>({user:stores.user})} | ||
render={props => (<NameDisplayer name={props.user.name}/>)} | ||
/> | ||
) | ||
|
||
const App = () => ( | ||
<Provider userStore={user}> | ||
<UserNameDisplayer /> | ||
</Provider> | ||
) | ||
``` | ||
|
||
### Global error handler with `onError` | ||
|
||
If a component throws an error, this logs to the console but does not 'crash' the app, so it might go unnoticed. | ||
|
@@ -438,3 +486,5 @@ Data will have one of the following formats: | |
|
||
WeakMap. Its `get` function returns the associated reactive component of the given node. The node needs to be precisely the root node of the component. | ||
This map is only available after invoking `trackComponents`. | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
import { Atom, Reaction, extras } from "mobx" | ||
import { Component } from "react" | ||
import React, { Component } from "react" | ||
import { findDOMNode as baseFindDOMNode } from "react-dom" | ||
import EventEmitter from "./utils/EventEmitter" | ||
import inject from "./inject" | ||
|
@@ -349,12 +349,41 @@ function mixinLifecycleEvents(target) { | |
} | ||
|
||
// TODO: support injection somehow as well? | ||
export const Observer = observer(({ children }) => children()) | ||
export const Observer = observer(({ children, inject: observerInject, render }) => { | ||
const component = children || render | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am thinking if there shouldn't be some warning if both props are used. Perhaps that's what you had in mind with that propTypes check? Except you need to return message describing a problem. Returning undefined means it's valid. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ennn , thinging, first i prefer show warning by propTypes if both props
'>< but seem complexity There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yea, checking with prop types like this is probably enough. I don't think it adds complexity, it's a friendly behavior toward user. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. great ! |
||
if (typeof component === "undefined") { | ||
return null | ||
} | ||
if (!observerInject) { | ||
return component() | ||
} | ||
const InjectComponent = inject(observerInject)(component) | ||
return <InjectComponent /> | ||
}) | ||
|
||
Observer.displayName = "Observer" | ||
|
||
Observer.propTypes = { | ||
render: (propValue, key, componentName, location, propFullName) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. DRYing this would be nice :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ennnn Any suggestion to diy Observer.propTypes There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, if you look closely, it's the same function except for that first condition. Which doesn't make any sense to me. It means, that when checking |
||
if (typeof propValue["children"] === "function") { | ||
return | ||
} | ||
if (typeof propValue[key] !== "function") | ||
return new Error( | ||
"Invalid prop `" + | ||
propFullName + | ||
"` of type `" + | ||
typeof propValue[key] + | ||
"` supplied to" + | ||
" `" + | ||
componentName + | ||
"`, expected `function`." | ||
) | ||
}, | ||
children: (propValue, key, componentName, location, propFullName) => { | ||
if (typeof propValue["render"] === "function") { | ||
return | ||
} | ||
if (typeof propValue[key] !== "function") | ||
return new Error( | ||
"Invalid prop `" + | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I did not mean this line to be included there as well, that's why I used italic ;)