Comments (20)
A link to my code:
https://github.com/loganpowell/RAATS/blob/master/src/index.js#L25
from curi.
Hold on... I think I might have zero'd in on it!
from curi.
Just for posterity, the issue is that you are using pathnames in your <Link>
s when all you really need to use are the route's name
s.
-<Link to="/">Home</Link>
+<Link to="Home">Home</Link>
-<Link to="/subpage">Subpage</Link>
+<Link to="Subpage">Subpage</Link>
-<Link to="/courses">Courses</Link>
+<Link to="Courses">Courses</Link>
from curi.
Aha! That was it. I was way off
from curi.
Sometimes its more characters (Home
vs /
), but I really like not having to care about pathname
s in my code.
from curi.
For my sake (and for other beginners), why have you chosen to pack the app under a render
function instead of providing a <Provider>
API like Apollo, RR, Styled-Components, etc...
from curi.
Do you mean why this
<CuriBase ... render={render} />
and not this?
<CuriBase ...>
<App />
</CuriBase>
from curi.
Yes... I'm looking at the Redux example and it feels like the Curi API is in a number of locations (I was hoping for a "centralized" experience ;). I'm sorry if it's less complex than it looks to me
from curi.
I'm just trying to help
from curi.
There are a few reasons, although it might just come down to being personal preference.
The <CuriBase>
is essentially the same as a <Provider>
, but with a different name. It has two functions:
- To call its
render
prop function whenever it re-renders, which in turn will re-render the application. This could be replaced withchildren
, but I'll get into why I prefer therender
prop. - To make variables accessible through React's
context
so that you don't have to manually pass theresponse
,router
, andnavigation
down through every component. React is actually changing how thecontext
works, so this might change soon. Since Curi really hasn't picked up steam yet (and it's still in beta), I might look into switching over to only the new method, but I'm not sure about the details of that yet and what changes@curi/react
might need to implement that.
So why a render
prop? The root child of the <CuriBase>
is where an app "starts", and so it needs the response
object in order to know what to render. Using a render
prop (it doesn't always have to be under the render
prop, children
is what React's new context
will use) allows you to explicitly inject the response
(and the navigation
and router
if you would like) into this root.
<CuriBase ... render={(response, navigation) => {
// every time the <CuriBase> re-renders, this will be called
// with the new response/navigation objects
return <App response={response} />;
}} />
To get the same functionality by passing a child element to <CuriBase>
, you would either have to pass these props yourself, the <CuriBase>
would internally have to use React.cloneElement
to inject those props, or you would have to wrap the root in a <Curious>
.
// explicitly pass props
router.respond((response, navigation) => {
ReactDOM.render((
<CuriBase ...>
<App response={response}/>
</CuriBase>
), holder);
});
// implicitly pass props
class CuriBase extends React.Component {
render() {
const { router, response, navigation, children } = this.props;
// need to make sure there is only one child element
const child = React.Children.only(children)
return React.cloneElement(child, { router, response, navigation });
}
}
<CuriBase ...>
<App /> {/* router, response, and navigation will be injected */}
</CuriBase>
// use Curious to inject props, which uses a render prop like the current CuriBase
<CuriBase ...>
<Curious render={curiProps => <App {...curiProps} />} />
</CuriBase>
Just for a comparision, in React Router the root component doesn't actually have access to routing props, so if you need them there, you end up having to wrap that component in a <Route>
.
// if you just render an App inside a Router,
// it doesn't get the history, match, or location
<BrowserRouter>
<App />
</BrowserRouter>
// you have to use withRouter or Route to inject those
<BrowserRouter>
<Route component={App} />
</BrowserRouter>
const withApp = withRouter(App)
<BrowserRouter>
<App />
</BrowserRouter>
from curi.
Damn man. You make me feel bad when you put this much into responding to my naive questions! Thank you. I guess it will just take some getting used to.
π
from curi.
If it makes more sense to you, just inline the render
function.
<CuriBase
...
render={response => (
<div>
<response.body response={response} />
</div>
)}
/>
Using a separate function is only minimally more efficient (with an inline function, a new function is created every render) but might make things more difficult to keep track of. The biggest benefit of a separate render function for me is that you don't have a bunch of import
s at the top of your index.js
file.
Do you think that the tutorial would be more straightforward with an inline render
prop? I have no problem switching to that.
from curi.
So, please bear with me as I don't exactly know how stupid my questions are and therefore assume they are all either stupid or misplaced (forgive me, with all respect).
How difficult would it be for me to 'mimic' the API of RR? Just so I could get going with Curi in a "drop-in" like manner? I figure some people will want to give this a try (like me) with an existing setup and butt-load of libraries (Apollo, Redux, etc.) adding a route.js config of course, in a "Migrating from RR" or something like that - tutorial. Just so folks can build out the mental model of Curi's API without having to start with a tabula rasa - unless "we must unlearn what we have learned", which would also be fine if it's necessary. Just kinda spit-balling here, please don't assume I'm your average customer. I'm a super newb!
How inefficient is this:
class CuriBase extends React.Component {
render() {
const { router, response, navigation, children } = this.props;
// need to make sure there is only one child element
const child = React.Children.only(children)
return React.cloneElement(child, { router, response, navigation });
}
}
and then:
class App extends Component {
render() {
return (
<CuriBase>
<ApolloProvider client={client}>
<ThemeProvider theme={censusMineral}>
<div className="App">
<div className="TopBar">
<Link to="Home">Home</Link>
<Link to="Subpage">Subpage</Link>
<Link to="Courses">Courses</Link>
</div>
<AnimatedRoutes>
<BodyComponent.../>
</AnimatedRoutes>
</div>
</ThemeProvider>
</ApolloProvider>
</CuriBase>
);
}
}
export default App;
I guess I'm kinda wondering if there are any ways I can shrink the API and kinda forget about it, ykwim?
from curi.
Edit: I erased this and didn't paste it back in:
I think there could be a "Beginners" path and then, maybe more advanced topics. To be completely fair, your tutorial is very straight forward! I am just trying to memorize the API, which will always take time.
from curi.
There isn't anything inefficient with cloneElement
(it is just making a copy of an object than adding some additional properties to it). My main concern is the "magic" involved there. I like to see the props getting passed to a component.
As far as other providers go, I would recommend wrapping those around the <CuriBase>
.
<ApolloProvider client={client}>
<ThemeProvider theme={censusMineral}>
<CuriBase
router={router}
response={response}
navigation={navigation}
render={response => (
<div className="App">
<div className="TopBar">
<Link to="Home">Home</Link>
<Link to="Subpage">Subpage</Link>
<Link to="Courses">Courses</Link>
</div>
<AnimatedRoutes>
<response.body .../>
</AnimatedRoutes>
</div>
)}
/>
</ThemeProvider>
</ApolloProvider>
I think that I'm going to add a <ResponsiveBase>
component to the @curi/react
and @curi/react-native
packages. That can automatically re-render when a new response is emitted (similar to wrapping <CuriBase>
in a connect
for Redux users).
// { once: true } means that this response handler will only be called
// once and the <ResponsiveBase> will take care of re-rendering
router.respond(() => {
ReactDOM.render((
<ApolloProvider client={client}>
<ThemeProvider theme={censusMineral}>
<ResponsiveBase router={router} render={...} />
</ThemeProvider>
</ApolloProvider>
), holder)
}, { once: true });
I should also write a migrating from RRv4 guide. RRv4 is really the odd one out as far as routers go; most other routers are similar to Curi.
Another change that I think should be made are the arguments passed to the <CuriBase render>
. Right now, it receives three arguments: response
, navigation
, and router
. However, I think those should be grouped under a single object. Then, the render
prop would effectively be passed a stateless React component.
const App = ({ response }) => (
<response.body />
);
<CuriBase ... render={App} />
from curi.
Right now, it receives three arguments: response, navigation, and router. However, I think those should be grouped under a single object.
I like that a lot!
There's still this kinda "hairy elbow" though:
router.respond(() => {
ReactDOM.render((
<ApolloProvider client={client}>
<ThemeProvider theme={censusMineral}>
<ResponsiveBase router={router} render={...} />
</ThemeProvider>
</ApolloProvider>
), holder)
}, { once: true });
This kinda makes me feel like Curi is taking over my app. Could it take some cues from the cross-platform Apollo Client
?
import curi, { CuriContext } from "@curi/core";
import { CuriBase } from "@curi/react";
import routes from "./routes";
import renderFunction from "./render";
const history = Browser();
const router = curi(history, routes);
const context = new CuriContextt({
router={router}
response={response}
navigation={navigation}
});
ReactDOM.render(
<CuriBase context={context}>
<MyAppComponent />
</CuriBase>,
document.getElementById('root')
)
I don't know how much of your API has been designed around the VDOM-agnosticism, so - again - forgive me if this is an important part of the implementation.
from curi.
I've been abandoning my family for a few days, so I have to peel away from the computer tonight, but I'll be back manjana!
πΊπΈ
from curi.
I appreciate the time you have taken and the feedback that you have given, but family is much more important. Also, while I (with bias) think that Curi is better than React Router, I also realize that RR is nearly ubiquitous with React devs, so please don't feel like you need to use Curi over RR. I hope it really grows and becomes a viable alternative, but there is a long way to go.
Once you do get back, as far as "Curi is taking over my app" goes, is it the router.respond
that you're concerned with? The reason that that exists is to delay rendering until a response
has been created. You can skip that, but the problem is that you have to figure out what to render before the first response
is emitted (in React Native, where you cannot wait for the initial response, I have just used a <Text>Loading...</Text>
).
const router = curi(history, routes);
ReactDOM.render((
<ResponsiveBase router={router} render={({ response }) => {
if (!response) { return <div>Loading...</div>; }
return (
<div>
<response.body response={response} />
</div>
);
}} />
), holder);
#9 adds a synchronous mode to Curi, which would mean you don't have to wait for the initial response, but it also means that you cannot use either match.initial
or match.every
(those are asynchronous, so Curi has to wait for those to finish before it can emit a response). I'm still debating whether or not to merge that, but I probably will.
from curi.
from curi.
from curi.
Related Issues (20)
- [React] CSS not loading when using redirectTo HOT 35
- React Packages v2 Plans HOT 2
- Parent Resolve Correlation to Child Route HOT 3
- You should be on Awesome x: HOT 1
- Offscreen positioning possibly bad for RTL languages HOT 2
- 'process' is not defined HOT 6
- SyntaxError: Unexpected token < HOT 5
- .html > .svelte HOT 1
- useRouter not updating state without useResponse HOT 2
- Navigation not working if using svelte beyond v3.6.4 HOT 6
- Pass server side response to client side router on creation HOT 3
- It appears that when I change the url the entire app is re-rendered HOT 1
- Customizing styles of `useNavigationFocus` / ref HOT 2
- How do I change route programmatically HOT 2
- [Feature] Redirect to url HOT 4
- Typescript Type Error for <Link> HOT 3
- Apollo Integration - Prefetching HOT 4
- webiste on different folder structure HOT 5
- @curi/static and svelte HOT 6
- Undefined value for optional route parameter HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. πππ
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from curi.