Skip to content
This repository has been archived by the owner on Dec 31, 2020. It is now read-only.

Add Observer render and inject sugar #387 #403

Merged
merged 9 commits into from
Feb 4, 2018

Conversation

Sunshine168
Copy link
Contributor

No description provided.

@danielkcz
Copy link
Contributor

danielkcz commented Jan 30, 2018

Just a hint, it might be easier to review this if you turn off Prettier :) (or perhaps eslint autofix?). Any kind of reformatting should be done in a separate PR in my opinion.

And I love this, that's mostly what I suggested in #387

Edit: Oh and would you mind updating Typescript definitions as well?

@Sunshine168
Copy link
Contributor Author

Sunshine168 commented Jan 31, 2018

@FredyC
Oh i got a hobby which formate code anytime. i check package seem husky not be added, so precommit did not work well.
i thought the rep should be format by same coding style and precommit should work, following this the code will be easier to review

hhhh, i very appreciate your suggestion ,so i did it and will update typescript definitions later

@danielkcz
Copy link
Contributor

danielkcz commented Jan 31, 2018

Yea, you are right, husky is not installed so precommit hook is not working. I've made another PR #407 to fix that. Once that gets merged, you can simply rebase this (some conflicts might happen) and only relevant changes will be part of this PR.

@mweststrate
Copy link
Member

@Sunshine168 Thanks for the PR! @FredyC's PR is merged, could you rebase?

PR looks good :). One remaining question; could you update the Readme as well describing this alternative syntax?

@danielkcz
Copy link
Contributor

Also, it's obvious that using children has a priority, but there should be test showing a use of both at once. And reflect this in docs as well.

@Sunshine168
Copy link
Contributor Author

i will rebase later , i am still in working

@Sunshine168
Copy link
Contributor Author

done !

README.md Outdated
@@ -82,7 +82,7 @@ It takes as children a single, argumentless function which should return exactly
The rendering in the function will be tracked and automatically re-rendered when needed.
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.

And it can work with `Provider` use inject and render property / or just takes as children, detail in Example2.(PS:using children has a priority than render , so dont use at the same time)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would split this, there are two concerns to cover - render prop and injecting. Also, I have a trouble understanding what it says. Let me rephrase this.

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

Observer can also inject the stores simply by passing a selector function.

Second example with inject

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh and with injecting it's worth to show an example that passing strings work same way as with inject HoC.

README.md Outdated
class App extends React.Component {
render() {
return (
<Provider h="hello" w="world">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure you can pass a string as a store prop? I am not aware that it would turn to observable automagically here. In that case, it's kinda misleading example.

src/observer.js Outdated

Observer.displayName = "Observer"

Observer.propTypes = {
render: (propValue, key, componentName, location, propFullName) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DRYing this would be nice :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ennnn Any suggestion to diy Observer.propTypes

Copy link
Contributor

Choose a reason for hiding this comment

The 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 render prop, you are telling it's ok if children prop is a function. That doesn't make any sense to me.

README.md Outdated
@@ -82,7 +82,7 @@ It takes as children a single, argumentless function which should return exactly
The rendering in the function will be tracked and automatically re-rendered when needed.
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.

And it can work with `Provider` use inject and render property / or just takes as children, detail in Example2.(PS:using children has a priority than render , so dont use at the same time)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh and with injecting it's worth to show an example that passing strings work same way as with inject HoC.

@Sunshine168
Copy link
Contributor Author

@FredyC Ohhhh very thank you for your help .tat now will be better?

README.md Outdated
const Comp = () => (
<div>
<Observer
inject={store => ({ h: store.h, w: store.w })}
render={props => <span>{`${props.h} ${props.w}`}</span>}
render={() => <span>hello world</span>}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, not very good example since there is nothing to observe :D Perhaps pass some variable in props to Comp and use that in render so it makes more sense.

README.md Outdated
Example2:
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
Copy link
Contributor

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 ;)

src/observer.js Outdated

Observer.displayName = "Observer"

Observer.propTypes = {
render: (propValue, key, componentName, location, propFullName) => {
Copy link
Contributor

Choose a reason for hiding this comment

The 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 render prop, you are telling it's ok if children prop is a function. That doesn't make any sense to me.

Copy link
Contributor

@danielkcz danielkcz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are getting there, some small tweaks are remaining.

README.md Outdated
@@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The 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 :)

README.md Outdated

Observer can also inject the stores simply by passing a selector function.

Example with inject
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for this line, it's redundant imo.

@@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ennn , thinging, first i prefer show warning by propTypes if both props
and coding like this

const ObserverPropsCheck = (props,key,componentName,location,propFullName)=>{
    const extraKey = key === "children" ? "render" : "children"
    if(typeof propValue[key] === "function" && typeof propValue[extraKey] === "function" ){
            return new Error("Invalid prop,do not use children and render in the same time in`" + componentName )
    }
    
    if (typeof propValue[key] === "function" || typeof propValue[extraKey] === "function") {
        return
    }
    return new Error(
        "Invalid prop `" +
            propFullName +
            "` of type `" +
            typeof propValue[key] +
            "` supplied to" +
            " `" +
            componentName +
            "`, expected `function`."
    )
}

'>< but seem complexity
or do same props check in Observer Component instead in propType

Copy link
Contributor

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great !

Copy link
Contributor

@danielkcz danielkcz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mweststrate I think we are good to go here :)

README.md Outdated
<div>
{this.props.person.name}
<Observer
render={(props) => <div>{props.person.name}</div>}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

props work without inejction?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, this is an oversight. It should refer to this.props instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry ,a stupid fault zzzzzz should refer to this.props

@mweststrate
Copy link
Member

Great work @Sunshine168 and thanks for the extensive reviews @FredyC and @Gvozd ! Will release tomorrow

@mweststrate mweststrate merged commit d921747 into mobxjs:master Feb 4, 2018
@mvestergaard
Copy link

This is broken. Results in Warning: Failed prop type: propValue is not defined errors due to usage here https://github.com/mobxjs/mobx-react/blob/master/src/observer.js#L368

@danielkcz
Copy link
Contributor

@mvestergaard That's an unfortunate oversight. Could you send in the PR please? Some tests for this should be probably included as well.

@mweststrate
Copy link
Member

Just released 4.4.1, that should fix the issue. Unclear yet why this passed the tests, so if somebody could add a test testing the prop types checking that would be appreciated :D

@github-actions github-actions bot mentioned this pull request Oct 13, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants