Relay Modern purpose of createFragmentContainer - javascript

I've been trying relay-modern for some time, and I'm wondering what are the purposes of createFragmentContainer other than just for describing the fragment that should beloing to the Component.
e.g. this is how documentation show how it is supposed to be
Parent.js
<QueryRenderer
render={({error, props}) => {
if (error || props) {
return <Child someData={someData}>
}
return <div>Loading</div>
}}
query={graphql`
query SomeQuery($id: ID!) {
endpoint(id: $id) {
...Child_someData
}
}
`}
/>
Child.js
export default createFragmentContainer(
({someData}) => <header>{someData.title} - {someData.name}</header>,
graphql`
fragment Child_someData on EndPoint {
title
name
}
`
)
But instead doing Child.js in that way, I can just rewrite or splitting the component with query to 2 different files like this:
ChildComponent.js
export default ({someData}) => <header>{someData.title} - {someData.name}</header>
Child.js
export default graphql`
fragment Child_someData on EndPoint {
title
name
}
`
and it is still going to work (Parent.js will still recognize the fragment). So this makes me wondering if createFragmentContainer just for syntactic sugar to make things tidier.
If anyone can shed a light with this one, that would be awesome! can't find so much in the documentation about this

Your example if a fairly static implementation... I think what you need to consider is that these are containers that provide additional functionality, fragmentContainer being one of the more abstract layers.
I would look more at how the refetchContainer and paginationContainer expand upon the idea of a fragmentContainer and also look at the Github repository itself,
https://github.com/facebook/relay/blob/master/packages/react-relay/modern/ReactRelayFragmentContainer.js
So certainly child containers could simply be a file filled with fragments that you are exporting out, but ideally you should think of them as containers which are extensions of React components. They are container fragments that bubble up into a compositional query which afford you conveniences for managing state in the context of React.

Relay compiler will find your Child.js file so the fragment will be created and your query will be fetched.
However, the difference is createFragmentContainer is a HOC that Relay uses to guarantee that the component won't render until all necessary data is available. This is the purpose of FragmentContainer and that's why you should use it.

Related

Access Relay state without passing down props

I'm learning Relay now and I was wondering if there is a way to access the state without having to pass down props. I thought that Relay used React Context, however, in all the examples they seem to be using props to pass down state instead of directly accessing the Context store. Is it possible to access state through Context? If so, is it considered bad practice?
My concern is that I will start to have a lot of props being passed down to components. In addition, it is difficult to pass down props to certain components in my application.
It is a bad practice to pass down Relay state using context, redux, or some other kind of external store. One of the core features of the library is making sure all components who need a piece of data get that piece, and no other pieces. This is one of the reasons Relay uses a compiler.
With Relay, developers use a declarative language called GraphQL to specify what data each component needs, but not how to get it.
[The compiler] allows components to be reasoned about in isolation, making large classes of bugs impossible
Subcomponents should use fragments. For example:
// User.tsx
interface UserProps {
initialQueryRef: PreloadedQuery<UserQuery>
}
export default function User({ initialQueryRef }: UserProps) {
const { user } = usePreloadedQuery(
graphql`
query UserQuery($uid: String!) {
user(uid: $uid) {
uid
...Avatar_fragment
...Biography_fragment
# ...
}
}
`,
initialQueryRef
)
return (
<div>
<Avatar user={user} />
<Biography user={user} />
{/* ... */}
</div>
)
}
// Biography.tsx
interface BiographyProps {
user: Biography_fragment$key // compiler generated type
}
export default function Biography({ user }: BiographyProps) {
const { shortBio, longBio } = useFragment(
graphql`
fragment Biography_fragment on User {
shortBio
longBio
}
`,
user
)
// ...
}
Relay will take care of updating the components that use fragments whenever the fragment data changes due to mutations, subscriptions, etc. You should never have to think about managing their state programmatically.

Filtering a list of names with ReactJS using data from RelayJS without calling GrpahQL

I'm stuck in wondering if I can filter a list of names which I receive from Relay and graphql-java server without the need of making calls, without making any changes in my GrpahQL schema and only using ReactJS for this purpose.
---MobX as a state management library can be a decision but I should first store all the Relay result.
Caveat emptor: I'm newish at Relay as well & struggling with these same concepts. But, given the relative dearth of accessible information on Relay, I thought it'd be helpful to try and layout the key concepts here. My understanding could be wrong, so I'd love it if anyone who found a mistake in my code/reasoning would comment/edit.
Filtering took awhile for me to 'click' as well. It depends on where you keep the data you'll use to filter, but let's assume the name field lives on your Users Type, and the query is something like this:
viewer {
allUsers {
edges {
node {
name
}
}
}
}
And let's say your top-level NameList component looked like this:
class NameList extends Component {
render() {
return (
<div>
{this.props.users.edges
.map(u => {
<NameItem name={u.node} />
})
}
</div>
)
}
}
Relay.createContainer(NameList, {
initialVariables: { first: 10 },
fragments: {
users: () => Relay.QL`
fragment on Viewer {
allUsers(first: $first) {
edges {
node {
${NameItem.getFragment('user')}
}
}
}
}
`
}
})
And your NameItem setup was simply:
class NameItem extends Component {
render() {
return (
<div>
Name: {this.props.user.name}
</div>
)
}
}
Relay.createContainer(NameItem, {
initialVariables: {},
fragments: {
user: () => Relay.QL`
fragment on User {
name
}
`
}
})
Consider the generalizable pattern here:
The List Component
A List component takes a fragment on the top-level Type in the query--in this case, Viewer, from a Relay container.
List also inserts a fragment on behalf of its Item child at the level of the User Type.
In other words, it captures an array of User objects it's supposed to pass down to the Item component.
If this wasn't Relay, and instead was, say, Redux, this component might simply pass state.users to the Item component. You can do that because, at some point, you've manually extracted all your Users from your own back-end and loaded them into Redux. But since Relay does the hard thinking for you, it needs a teensy bit more information than Redux.
The Item Component
This is even more simple. It expects an entity of type User and renders the name. Besides syntax, the functionality here isn't much different from a similar component in a Redux setup.
So really, without the complexity of Relay on top, all you have is an array of items that you're rendering. In vanilla React, you'd simply filter the array prior to (or during) your call to .map() in render().
However, with Relay, the fragment handed to the child is opaque to the parent--i.e., the List is handing a blind package to the Item, so it can't make a decision on whether or not to pass it down based on the fragment's content.
The solution in this contrived example is pretty simple: just peel-off the name field at the parent and child level. Remember: Relay is about components telling GraphQL what data they need. Your List component needs whatever fields it intends on filtering on--no more, no less.
If we modify the above List container:
...
users: () => Relay.QL`
fragment on Viewer {
allUsers(first: $first) {
edges {
node {
name
${NameItem.getFragment('user')}
}
}
}
}
`
And then we update our render function:
<div>
{this.props.users.edges
.map(u => {
if (u.node.name == "Harvey") {
<NameItem name={u.node} />
}
})
}
</div>
Then we've achieved basic filtering without needing mobx, more server trips, etc.

is there such a thing as JSX 'partials'?

I work mainly with Handlebars JS now, but I am looking at JSX. Is there a JSX equivalent to Handlebars partials? I want to know if I can create small bits of markup that I can reuse in several different JSX views.
It doesn't provide partials. Some things about React:
React doesn't provide any notion of partials. The fundamental, atomic unit of React is the component.
Instead of passing a partial, you'd create a component or components and re-use those. Even better than a partial because it's a function, so it's encapsulated and testable!
If the markup is small, it should probably either be moved up into a parent component or down into a simpler one
Generally, my rule of thumb is that components should follow the principle of single responsibility or separation of concerns. If something doesn't seem to fit into a component, you've likely got problems in the other two components and could reconsider them, too :)
Another couple rules of thumb to go by when thinking about components:
code smells should usually end up as components (repeating something over and over again, etc.)
components are usually either presentational or containerized. The latter have roles in the props/state tree for an app (you never "see them")
refactor things into components as you need to; don't start out encapsulating everything, because you may have prematurely refactored and created more problems for yourself
the most reusable and decoupled components are like the best functions or objects: clean, flexible, testable, and they do address a single concern
at the same time, don't go crazy and turn everything into a component. i.e. you don't (usually) want:
<Letter>R</Letter><Letter>e</Letter><Letter>a</Letter><Letter>c</Letter><Letter>t</Letter>
Here's an incredibly simple example:
'use strict';
const OuterComponent = React.createClass({
render() {
return (
<div>Outer{this.props.children}</div>
);
}
});
const ReusableComponent = React.createClass({
render() {
return (
<div>Am I reusable? {this.props.reusable && 'Yeah!' }</div>
);
}
});
ReactDOM.render(
<OuterComponent>
<ReusableComponent reusable={true}/>
</OuterComponent>,
document.getElementById('container')
);
Will render:
OuterComponent
Am I reusable? Yeah!
Note, though, that using creatClass provides you more than you might need if you're not working with mutable state (which is provided to you within the component via this.state), you can easily use what are sometimes called "stateless functional components" (because they are, well, stateless and returned by functions). These could easily be arrow functions implicitly returning the JSX (which is essentially just React.createElement() generator)
const OuterComponent = (props) => <div>Outer{this.props.children}</div>;
const ReusableComponent = (props) => <div>Am I reusable? {this.props.reusable && 'Yeah!' }</div>;
ReactDOM.render(
<OuterComponent>
<ReusableComponent reusable={true}/>
</OuterComponent>,
document.getElementById('container')
);
Just create a component for that. Components can be as simple or as complex as you want them to be.
Example:
function Badge(props) {
return <span className="badge">{props.counter}</span>
}
With a corresponding .badge CSS class, this could be a very simply component that renders as a red circle with a number, and is used as <Badge counter={42} />.

What's the difference between using a stateless functional component versus calling a method?

I'm trying to understand stateless components and what the difference is between these examples:
class App {
render() {
return (
<div>
{this.renderAFunction('hello')}
</div>
);
}
renderAFunction(text) {
return (
<p>{text}</p>
);
}
}
and this:
class App {
render() {
return(
<div>
<RenderAFunction text='hello'/>
</div>
);
}
}
const RenderAFunction = ({text}) => (
<p>{text}</p>
);
Or if there is any difference at all?
Functionally, there is absolutely no difference. Both end up rendering a paragraph element, but there are other aspects to consider. There are three points to make (in my opinion) when examining both methods:
Reusability: You have to understand to separate components when you need to. If renderAFunction is just meant to generate some JSX based on, for example, an API request, then it's fine being in a method. But if you want to reuse it somewhere else, then separate it into it's own component. A huge part of React is component reusability and getting rid of code duplication. Separating the method into it's own component would be imperative to accomplish this.
Purpose: There are reason to use stateless function components and reasons not to. The whole point of stateless functional components is to not have state and be presentational. If you need to do something that involves the React lifecycle or internal state, keep it as a method, or new class depending on if you want it reusable.
Performance: Using a stateless functional component would be less efficient. This is because it's a component, not just some JSX returned from a method. As of right now, the React team plans on making some optimizations for stateless functional components because they do not contain state and are merely presentational, but this probably won't happen until after React Fiber is done and thus your stateless functional component has no optimizations versus a regular full-fledged class component. That makes it incredibly inefficient versus a method returning some JSX, especially if it's just used once in another component.
A good rule of thumb is to ask yourself, do I need it anywhere else? If not, then keep it in a method. If you don't need it anywhere else, separating the JSX into a separate component would have worse performance and wouldn't follow React's core principles.
If you are going to need it somewhere else, then separate the component so you follow React's concept of reusability.
Your App's render function will be translated into following JS code for your first example:
render() {
return React.createElement(
'div',
null,
this.renderAFunction('hello')
);
}
And the following one for the second one:
render() {
return React.createElement(
'div',
null,
React.createElement(RenderAFunction, { text: 'hello' })
);
}
While they both looks almost the same, there is one significant difference: laziness. React will execute RenderAFunction body only in case it gonna be mounted to the DOM hierarchy.
It is insignificant is your case, but imaging following example:
const LazyApp = () => {
const heavy = <div><HeavyStuff /></div>
// ...
return <div>done it</div>
}
const HardWorkingApp = () => {
const heavy = <div>{HeavyStuff()}</div>
// ...
return <div>done it</div>
}
const HeavyStuff = () => {
// ... do heavy rendering here
}
Lazy app will not perform any heavy stuff at all. Maybe it is not very clear from that synthetic example why one would do anything like that at all. But there are real-world examples out there, when something conceptually similar (creating Components without rendering them) is happening.
Basically, both will serve the same purpose. But the real advantage of creating a component is its reusability.
If you have to render that particular piece of jsx just for this component. Then, there is no need to create a separate component.

How should I use redux with nested subcomponents that won't be reused?

I'm working on a component that has many subcomponents, some of which are nested five deep. I'm interested in using redux for the advantage of having a single source of truth in a common state atom.
What I'm not understanding is the smart/dumb component recommendation and putting the provider above the main component and passing everything down via props. If I do this then I'd need to pass props down all the way to the fifth nested item so it can make a callback to dispatch an action or to look at some state that only it needs and not its parents. I understand this is for code reuse, but the subcomponents will never be used outside of the main component. What is the recommended solution here? Still use props?
Note: the author of this library requested we ask questions on StackOverflow. I'm mentioning this because SO seems to flag "best practice" questions as too vague.
While the answer matt clemens posted does cover this at a high level, but I'll try to go into more depth here.
You can use connect() at any level. Doing so makes the component smart, since it knows where its props come from. A dumb component just has props, and they could come from anywhere. A smart component is coupled to redux; a dumb component is not.
There are differing opinions on this approach, but it is supported and valid.
Where to draw this line is entirely up to you, but let's look at an example. You have some chat client with a standard sidebar component, a message window, and the entry field for sending new messages.
+---------+--------------------------+
| | |
|Sidebar | Messages window |
| | |
| | |
| | |
| | |
| +--------------------------+
| | New Message Entry **|
| | |
+---------+--------------------------+
The parent of all of these would use connect() to get the data from redux and feed it into these components via props. Now imagine that those two asterisks besides new message entry open up a settings panel (ignore the stupid placement, this is an example). Does it really make sense for new message entry to pass those props through? No, it doesn't.
To solve this you could create a special "container", lets call it SettingsContainer that used connect() to get its props and all it did was pass them down to SettingsPopup. SettingsPopup would not know about redux, and could still be tested/styled/reused normally, and the new message entry would only need to know about SettingsContainer, not any of its dependencies.
This approach scales well, but it has two penalties. First, the smart "wrapper" components like SettingsContainer have to be consumed by otherwise dumb components. This complicates the testing of the new message entry component. Second, the top-level component no longer exposes the entire graph of data dependencies, which makes things harder to reason about without delving deep into the component hierarchy.
These tradeoffs can be worth it, but you should be aware of them.
You can use the newer React feature of context, via using 'react-redux''s component Provider. Using Provider will abstract away some of the implementation details of context, makes your markup quite expressive imho.
You basically setup a mini-global property, that all sub-components, dumb or smart can reference:
import React from 'react';
import {render} from 'react-dom';
import {createStore} from 'redux';
import {Provider} from 'react-redux'; //Special Redux component to help
import {reducers} from './reducers.js';
var DeepDumbChild = (props, context) => (
<div>
<pre>
{JSON.stringify(data, null, 2)}
</pre>
</div>
)
class SmartChild extends React.Component {
render() {
/* Use the global-like context */
let data = this.context.store.getState();
return (
<div>
<DeepDumbChild data={data}/>
</div>
)
}
}
SmartChild.contextTypes = {
store: React.PropsTypes.object /* required */
}
/* No messy props :) */
var App = () => (<div>
<SmartChild/>
</div>);
render(
<Provider store={createStore(reducers)}>
<App/>
</Provider>,
document.getElementById('app')
);
UPDATE: If you want to try the approach below, have a look at https://github.com/artsy/react-redux-controller, which I recently published.
I think the best way to go is to map selectors to context at the root (container) component, rather than having a bunch of containers or using connect everywhere. I've done this in my own project and it's working beautifully. It adds a new pattern of annotating selectors with the PropTypes they produce. That let me use childContextTypes to allow all descendants to retain the same protections they have with propTypes. This is an advantage over Ashley Coolman's approach of passing down a big untyped object being passed down. I'm hoping to have time in the next couple days to factor it into its own library and publish.
In the meantime, I'd suggest making components smart, using connect liberally, rather than Tyrsius's approach of creating a whole bunch of containers, but that's just my opinion.

Categories