Determining when Relay is fetching query data - reactjs

I'm using Reactjs and Relayjs in my web application. One of the pages, I call it memberList, is displaying a list of all users registered on the website.
This is a simplified version of my implementation:
render() {
{this.props.memberList.edges.length > 0 ?
<ol>
{this.props.memberList.edges.map(
(member, i) => {
return <li>{member.node.username}</li>;
}
)}
</ol>
: <span>No members to show!</span>}
}
And my RelayContainer:
export default Relay.createContainer(MemberList, {
fragments: {
classroom: () => Relay.QL`
fragment on Classroom {
id,
memberList(first: 100) {
edges {
node {
id,
username
}
}
},
}
`,
},
});
This works fine; it displays all the members of the classroom as expected. However, the page doesn't behave quite as I'd like it to:
When navigating to the page, or when refreshing, the <span> is rendered for a brief moment, because the this.props.memberList.edges array is empty.
Less than one second later, the props update and the array is no longer empty. This causes a re-render and the <ul> list with the members is now displayed instead - as expected.
I want to know when Relay is fetching data so I can determine if the memberList is actually empty or if its' properties cannot yet be determined because a query response is pending.
How can this be accomplished? I've searched for over 2 hours and I can only find relevant answers to mutations, which is not what I'm doing here. Thanks.

I'm surprised that your component is briefly rendering the span. By default the component shouldn't even be rendered if Relay hasn't finished fetching data.
Anyway, if you figure out what is going on there, Relay.Renderer has a render prop that you can use to achieve what you want. Here's an example (taken directly from the docs).
In this example, ErrorComponent and LoadingComponent simply display a static error message / loading indicator.
<Relay.Renderer
Container={ProfilePicture}
queryConfig={profileRoute}
environment={Relay.Store}
render={({done, error, props, retry, stale}) => {
if (error) {
return <ErrorComponent />;
} else if (props) {
return <ProfilePicture {...props} />;
} else {
return <LoadingComponent />;
}
}}
/>
If you're using Relay.RootContainer, it has some a similar renderLoading prop.

Related

Making .map inside .map [duplicate]

In my component's render function I have:
render() {
const items = ['EN', 'IT', 'FR', 'GR', 'RU'].map((item) => {
return (<li onClick={this.onItemClick.bind(this, item)} key={item}>{item}</li>);
});
return (
<div>
...
<ul>
{items}
</ul>
...
</div>
);
}
everything renders fine, however when clicking the <li> element I receive the following error:
Uncaught Error: Invariant Violation: Objects are not valid as a React
child (found: object with keys {dispatchConfig, dispatchMarker,
nativeEvent, target, currentTarget, type, eventPhase, bubbles,
cancelable, timeStamp, defaultPrevented, isTrusted, view, detail,
screenX, screenY, clientX, clientY, ctrlKey, shiftKey, altKey,
metaKey, getModifierState, button, buttons, relatedTarget, pageX,
pageY, isDefaultPrevented, isPropagationStopped, _dispatchListeners,
_dispatchIDs}). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from
the React add-ons. Check the render method of Welcome.
If I change to this.onItemClick.bind(this, item) to (e) => onItemClick(e, item) inside the map function everything works as expected.
If someone could explain what I am doing wrong and explain why do I get this error, would be great
UPDATE 1:
onItemClick function is as follows and removing this.setState results in error disappearing.
onItemClick(e, item) {
this.setState({
lang: item,
});
}
But I cannot remove this line as I need to update state of this component
I was having this error and it turned out to be that I was unintentionally including an Object in my JSX code that I had expected to be a string value:
return (
<BreadcrumbItem href={routeString}>
{breadcrumbElement}
</BreadcrumbItem>
)
breadcrumbElement used to be a string but due to a refactor had become an Object. Unfortunately, React's error message didn't do a good job in pointing me to the line where the problem existed. I had to follow my stack trace all the way back up until I recognized the "props" being passed into a component and then I found the offending code.
You'll need to either reference a property of the object that is a string value or convert the Object to a string representation that is desirable. One option might be JSON.stringify if you actually want to see the contents of the Object.
So I got this error when trying to display the createdAt property which is a Date object. If you concatenate .toString() on the end like this, it will do the conversion and eliminate the error. Just posting this as a possible answer in case anyone else ran into the same problem:
{this.props.task.createdAt.toString()}
I just got the same error but due to a different mistake: I used double braces like:
{{count}}
to insert the value of count instead of the correct:
{count}
which the compiler presumably turned into {{count: count}}, i.e. trying to insert an Object as a React child.
Just thought I would add to this as I had the same problem today, turns out that it was because I was returning just the function, when I wrapped it in a <div> tag it started working, as below
renderGallery() {
const gallerySection = galleries.map((gallery, i) => {
return (
<div>
...
</div>
);
});
return (
{gallerySection}
);
}
The above caused the error. I fixed the problem by changing the return() section to:
return (
<div>
{gallerySection}
</div>
);
...or simply:
return gallerySection
React child(singular) should be type of primitive data type not object or it could be JSX tag(which is not in our case). Use Proptypes package in development to make sure validation happens.
Just a quick code snippet(JSX) comparision to represent you with idea :
Error : With object being passed into child
<div>
{/* item is object with user's name and its other details on it */}
{items.map((item, index) => {
return <div key={index}>
--item object invalid as react child--->>>{item}</div>;
})}
</div>
Without error : With object's property(which should be primitive, i.e. a string value or integer value) being passed into child.
<div>
{/* item is object with user's name and its other details on it */}
{items.map((item, index) => {
return <div key={index}>
--note the name property is primitive--->{item.name}</div>;
})}
</div>
TLDR; (From the source below) : Make sure all of the items you're rendering in JSX are primitives and not objects when using React. This error usually happens because a function involved in dispatching an event has been given an unexpected object type (i.e passing an object when you should be passing a string) or part of the JSX in your component is not referencing a primitive (i.e. this.props vs this.props.name).
Source - codingbismuth.com
Mine had to do with forgetting the curly braces around props being sent to a presentational component:
Before:
const TypeAheadInput = (name, options, onChange, value, error) => {
After
const TypeAheadInput = ({name, options, onChange, value, error}) => {
I too was getting this "Objects are not valid as a React child" error and for me the cause was due to calling an asynchronous function in my JSX. See below.
class App extends React.Component {
showHello = async () => {
const response = await someAPI.get("/api/endpoint");
// Even with response ignored in JSX below, this JSX is not immediately returned,
// causing "Objects are not valid as a React child" error.
return (<div>Hello!</div>);
}
render() {
return (
<div>
{this.showHello()}
</div>
);
}
}
What I learned is that asynchronous rendering is not supported in React. The React team is working on a solution as documented here.
Mine had to do with unnecessarily putting curly braces around a variable holding a HTML element inside the return statement of the render() function. This made React treat it as an object rather than an element.
render() {
let element = (
<div className="some-class">
<span>Some text</span>
</div>
);
return (
{element}
)
}
Once I removed the curly braces from the element, the error was gone, and the element was rendered correctly.
For anybody using Firebase with Android, this only breaks Android. My iOS emulation ignores it.
And as posted by Apoorv Bankey above.
Anything above Firebase V5.0.3, for Android, atm is a bust. Fix:
npm i --save firebase#5.0.3
Confirmed numerous times here
https://github.com/firebase/firebase-js-sdk/issues/871
I also have the same problem but my mistake is so stupid. I was trying to access object directly.
class App extends Component {
state = {
name:'xyz',
age:10
}
render() {
return (
<div className="App">
// this is what I am using which gives the error
<p>I am inside the {state}.</p>
//Correct Way is
<p>I am inside the {this.state.name}.</p>
</div>
);
}
}
Typically this pops up because you don't destructure properly. Take this code for example:
const Button = text => <button>{text}</button>
const SomeForm = () => (
<Button text="Save" />
)
We're declaring it with the = text => param. But really, React is expecting this to be an all-encompassing props object.
So we should really be doing something like this:
const Button = props => <button>{props.text}</button>
const SomeForm = () => (
<Button text="Save" />
)
Notice the difference? The props param here could be named anything (props is just the convention that matches the nomenclature), React is just expecting an object with keys and vals.
With object destructuring you can do, and will frequently see, something like this:
const Button = ({ text }) => <button>{text}</button>
const SomeForm = () => (
<Button text="Save" />
)
...which works.
Chances are, anyone stumbling upon this just accidentally declared their component's props param without destructuring.
Just remove the curly braces in the return statement.
Before:
render() {
var rows = this.props.products.map(product => <tr key={product.id}><td>{product.name}</td><td>{product.price}</td></tr>);
return {rows}; // unnecessary
}
After:
render() {
var rows = this.props.products.map(product => <tr key={product.id}><td>{product.name}</td><td>{product.price}</td></tr>);
return rows; // add this
}
I had the same problem because I didn't put the props in the curly braces.
export default function Hero(children, hero ) {
return (
<header className={hero}>
{children}
</header>
);
}
So if your code is similar to the above one then you will get this error.
To resolve this just put curly braces around the props.
export default function Hero({ children, hero }) {
return (
<header className={hero}>
{children}
</header>
);
}
I got the same error, I changed this
export default withAlert(Alerts)
to this
export default withAlert()(Alerts).
In older versions the former code was ok , but in later versions it throws an error. So use the later code to avoid the errror.
This was my code:
class App extends Component {
constructor(props){
super(props)
this.state = {
value: null,
getDatacall : null
}
this.getData = this.getData.bind(this)
}
getData() {
// if (this.state.getDatacall === false) {
sleep(4000)
returnData("what is the time").then(value => this.setState({value, getDatacall:true}))
// }
}
componentDidMount() {
sleep(4000)
this.getData()
}
render() {
this.getData()
sleep(4000)
console.log(this.state.value)
return (
<p> { this.state.value } </p>
)
}
}
and I was running into this error. I had to change it to
render() {
this.getData()
sleep(4000)
console.log(this.state.value)
return (
<p> { JSON.stringify(this.state.value) } </p>
)
}
Hope this helps someone!
If for some reason you imported firebase. Then try running npm i --save firebase#5.0.3. This is because firebase break react-native, so running this will fix it.
In my case it was i forgot to return a html element frm the render function and i was returning an object . What i did was i just wrapped the {items} with a html element - a simple div like below
<ul>{items}</ul>
Just remove the async keyword in the component.
const Register = () => {
No issues after this.
In my case, I added a async to my child function component and encountered this error. Don't use async with child component.
I got this error any time I was calling async on a renderItem function in my FlatList.
I had to create a new function to set my Firestore collection to my state before calling said state data inside my FlatList.
My case is quite common when using reduce but it was not shared here so I posted it.
Normally, if your array looks like this:
[{ value: 1}, {value: 2}]
And you want to render the sum of value in this array. JSX code looks like this
<div>{array.reduce((acc, curr) => acc.value + curr.value)}</div>
The problem happens when your array has only one item, eg: [{value: 1}].
(Typically, this happens when your array is the response from server so you can not guarantee numbers of items in that array)
The reduce function returns the element itself when array has only one element, in this case it is {value: 1} (an object), it causes the Invariant Violation: Objects are not valid as a React child error.
You were just using the keys of object, instead of the whole object!
More details can be found here: https://github.com/gildata/RAIO/issues/48
import React, { Component } from 'react';
import PropTypes from 'prop-types';
class SCT extends Component {
constructor(props, context) {
super(props, context);
this.state = {
data: this.props.data,
new_data: {}
};
}
componentDidMount() {
let new_data = this.state.data;
console.log(`new_data`, new_data);
this.setState(
{
new_data: Object.assign({}, new_data)
}
)
}
render() {
return (
<div>
this.state.data = {JSON.stringify(this.state.data)}
<hr/>
<div style={{color: 'red'}}>
{this.state.new_data.name}<br />
{this.state.new_data.description}<br />
{this.state.new_data.dependtables}<br />
</div>
</div>
);
}
}
SCT.propTypes = {
test: PropTypes.string,
data: PropTypes.object.isRequired
};
export {SCT};
export default SCT;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
If you are using Firebase and seeing this error, it's worth to check if you're importing it right. As of version 5.0.4 you have to import it like this:
import firebase from '#firebase/app'
import '#firebase/auth';
import '#firebase/database';
import '#firebase/storage';
Yes, I know. I lost 45 minutes on this, too.
I just put myself through a really silly version of this error, which I may as well share here for posterity.
I had some JSX like this:
...
{
...
<Foo />
...
}
...
I needed to comment this out to debug something. I used the keyboard shortcut in my IDE, which resulted in this:
...
{
...
{ /* <Foo /> */ }
...
}
...
Which is, of course, invalid -- objects are not valid as react children!
I'd like to add another solution to this list.
Specs:
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-redux": "^5.0.6",
"react-scripts": "^1.0.17",
"redux": "^3.7.2"
I encountered the same error:
Uncaught Error: Objects are not valid as a React child (found: object
with keys {XXXXX}). If you meant to render a collection of children,
use an array instead.
This was my code:
let payload = {
guess: this.userInput.value
};
this.props.dispatch(checkAnswer(payload));
Solution:
// let payload = {
// guess: this.userInput.value
// };
this.props.dispatch(checkAnswer(this.userInput.value));
The problem was occurring because the payload was sending the item as an object. When I removed the payload variable and put the userInput value into the dispatch everything started working as expected.
If in case your using Firebase any of the files within your project.
Then just place that import firebase statement at the end!!
I know this sounds crazy but try it!!
I have the same issue, in my case,
I update the redux state, and new data parameters did not match old parameters, So when I want to access some parameters it through this Error,
Maybe this experience help someone
My issue was simple when i faced the following error:
objects are not valid as a react child (found object with keys {...}
was just that I was passing an object with keys specified in the error while trying to render the object directly in a component using {object} expecting it to be a string
object: {
key1: "key1",
key2: "key2"
}
while rendering on a React Component, I used something like below
render() {
return this.props.object;
}
but it should have been
render() {
return this.props.object.key1;
}
If using stateless components, follow this kind of format:
const Header = ({pageTitle}) => (
<h1>{pageTitle}</h1>
);
export {Header};
This seemed to work for me
Something like this has just happened to me...
I wrote:
{response.isDisplayOptions &&
{element}
}
Placing it inside a div fixed it:
{response.isDisplayOptions &&
<div>
{element}
</div>
}

ReactJS sort by Asc/Desc not rendering sorted list from nested component

Project Overview
I am currently learning ReactJS and am creating a Pokedex app that allows the user to sort Pokemon objects by specific properties (name, type, hp, etc). The end product should have a search input to filter by pokemon name, a drop-down selector for sort criteria, and buttons for sort Ascend and sort Descend. State being tracked is searchQuery, sortBy, sortSelected, and pokeData(my data file).
Full code can be viewed here: https://github.com/julianne-vela/Pokedex-React/tree/dev
File Structure: SearchPage.js > SideBar.js > SortMenu.js
Problem
onClick button in SortMenu is not rendering sorted Pokemon list.
Expected Result: Click Asc/Desc button in SortMenu -> Pokemon list renders in sorted order based on criteria selected in drop-down and Asc/Desc button clicked.
Actual Result: Drop-down is updating state with correct sort criteria selected but button is not triggering any action when clicked.
What I've tried
Using destructured props throughout project
const {
sortBy,
sortSelected,
} = this.state
Currently passing the following props from SearchPage.js to child SideBar.js:
sortByValues={sortBy} // Array of sort criteria options stored in state
sortSelected={sortSelected} // Currently selected sort criteria from drop-down
handleSortSelected={this.handleSortSelected} // event handler to update state with currently selected sort criteria
sortAsc={this.sortAsc} // function to trigger Asc sort onClick
sortDesc={this.sortDesc} // function to trigger Asc sort onClick
SortMenu.js Code
import React, { Component } from 'react';
export default class SortMenu extends Component {
render() {
const {
sortByValues,
handleSortSelected,
sortAsc,
sortDesc,
} = this.props
const options = sortByValues.map(option => <option value={option} key={option}>{option}</option>)
return (
<aside>
{/* DropDown Sort By */}
<select className='dropdown'
onChange={handleSortSelected}>
{options}
</select>
{/* Sort Ascending/Descending Buttons */}
<button className='sortBtn' value='ascending' onClick={sortAsc}>Ascending</button>
<button className='sortBtn' value='descending' onClick={sortDesc}>Descending</button>
</aside >
)
}
}
I feel it's important to note that we are using strictly class components and therefore are not using constructor(props) in this project. Instead, I am using arrow functions throughout to implicitly bind this where needed.
To reiterate my goal: I need to dynamically render the pokemon list based on the sort criteria selected in the drop-down list as well as the ascend/descend button clicked. The list should update onClick.
I have been working on this for 3 days and have gone through so many iterations of sort functions that I can't even see straight anymore. I'm thinking this might be a simple over-sight due to the sheer amount of code I'm writing as well as the fact that this is a new language (I'm already proficient in Vanilla JS).
Any guidance here would be GREATLY appreciated as I'm really at a wall at this point. I don't know what else to try in order to render the sorted list.
Update
Also, would it be easier if I were to create a toggle button instead of two separate buttons for Asc/Desc?
Thank you!
Update 2
Currently I am rendering my pokemon objects in a module component that I'm calling within the SearchPage.js component. Here is the code for the Pokemon List:
export default class PokemonList extends Component {
render() {
const { filteredPokemon } = this.props
return (
<content className='pokemon-list float'>
{filteredPokemon.map(pokeObject =>
<PokeItem
key={pokeObject._id}
pokeImage={pokeObject.url_image}
pokeName={capFirstLetter(pokeObject.pokemon)}
pokeType={capFirstLetter(pokeObject.type_1)}
pokeHp={pokeObject.hp}
pokeAtt={pokeObject.attack}
pokeDef={pokeObject.defense}
/>)}
</content>
);
}
}
This is pulling the filtered pokemon from my filter method on SearchPage.js:
const filteredList = pokeData.filter(pokeObject => {
return pokeObject['pokemon'].includes(this.state.searchQuery) || pokeObject['type_1'].includes(tFilterSelected);
});
To sort the items, I'm using two separate arrow functions. These are housed in the first section of the SearchPage.js component (outside of render and return):
sortAsc = () => {
this.setState(prevState => {
this.state.pokeData.sort((a, b) => (a[this.state.sortSelected] - b[this.state.sortSelected]))
})
}
sortDesc = () => {
this.setState(prevState => {
this.state.pokeData.sort((a, b) => (b[this.state.sortSelected] - a[this.state.sortSelected]))
})
}
Update 3
Added project to CodeSandbox. Can view here: https://codesandbox.io/s/pokedex-react-crflb
A comparator function that subtracts the arguments would work fine for sorting numbers but would fail on strings since it would return NaN.
sortAsc = () => {
const { pokeData, sortSelected } = this.state
this.setState({
pokeData: [...pokeData].sort((a, b) => {
if (a[sortSelected] > b[sortSelected]) {
return 1
}
if (a[sortSelected] < b[sortSelected]) {
return -1
}
return 0
})
})
}
sortDesc = () => {
const { pokeData, sortSelected } = this.state
this.setState({
pokeData: [...pokeData].sort((a, b) => {
if (a[sortSelected] > b[sortSelected]) {
return -1
}
if (a[sortSelected] < b[sortSelected]) {
return 1
}
return 0
})
})
}
Working CodeSandbox

Call Typescript Apollo Query from componentDidMount()

I have a React Component that calls a Query that expects to receive an array of objects (for validation data). I then use it to validate an html form, that is in turn defined inside of an apollo Mutation element. The way it is structured within the return statement of the component render() method works but it looks cumbersome and it reminds me of the callback hell era. What I really want to do is to get rid of the <QueryCustomerValidations> element in the render() method and move it into (ideally) the componentDidMount lifecycle event. So that the validators can be loaded there for later use within the form, then leave the <MutationCreateCustomer>inside render().
Right now, I have to wrap the form inside the mutation. The mutation inside the arrow function that the query returns in order to receive the async data in the proper order.
//-------------------------------------------------------------------------
// Component Lifecycle Eventhandler Methods
//-------------------------------------------------------------------------
componentDidMount()
{
}
//-------------------------------------------------------------------------
// Render Method Section
//-------------------------------------------------------------------------
public render(): JSX.Element
{
// Return Form
return (
<React.Fragment>
{/* PAGE TITLE */}
<h2 className="text-center mb-3">Agregar Nuevo Cliente</h2>
{/* LOAD VALIDATIONS INTO STATE */}
<QueryCustomerValidations
query={Q_GET_CUSTOMER_VALIDATIONS}
>
{({ loading: loadingValidations, error: errorValidations, data: dataValidations }) =>
{
if (loadingValidations)
{
return "Cargando..."
}
if (errorValidations)
{
return `Error: ${errorValidations.message}`
}
if (dataValidations)
{
const validators: ValidationDescriptor[] = []
dataValidations.getCustomerValidations.forEach((validator) => {
validators.push(validator as ValidationDescriptor)
})
this.validators.setValidators(validators)
}
/* DATA ENTRY FORM */
return (
<div className="row justify-content-center">
<MutationCreateCustomer
mutation={M_CREATE_CUSTOMER}
onCompleted={() => this.props.history.push('/')}
>
{(createCustomer: any) => {
return (
<form name="frmNewCustomer"
className="col-md-8 m-3"
onSubmit={e => this.frmNewCustomer_submit(e, createCustomer)}
>
{ this.ctrl_form_layout(this.props, this.state, this.validators) }
</form>
)
}}
</MutationCreateCustomer>
</div>
)
}}
</QueryCustomerValidations>
</React.Fragment>
);
}
Here for documentation purposes are the interfaces to create the Query. Since I get some of this data from the server using the apollo client, a simple graphql query solution on the onDidMount() would not work in this case.
getCustomerValidations.ts (Interfaces)
// ====================================================
// GraphQL query operation: getCustomerValidations
// ====================================================
export interface getCustomerValidations_getCustomerValidations {
__typename: "ValidationDescriptor";
field: string | null;
type: string | null;
required: boolean;
max: number | null;
min: number | null;
regex: string | null;
}
export interface getCustomerValidations {
getCustomerValidations: getCustomerValidations_getCustomerValidations[];
}
customer-validations.query.ts (Client side query types)
//---------------------------------------------------------------------------------
// Imports Section (React/Apollo Libs)
//---------------------------------------------------------------------------------
import { gql } from 'apollo-boost';
import { Query } from 'react-apollo'
import { getCustomerValidations } from '../../typeDefs/operations/getCustomerValidations'
//---------------------------------------------------------------------------------
// GQL Query: Customers
//---------------------------------------------------------------------------------
export const Q_GET_CUSTOMER_VALIDATIONS = gql`
query getCustomerValidations {
getCustomerValidations
{
field
type
required
max
min
regex
}
}
`;
//---------------------------------------------------------------------------------
// Query Class: Customers
//---------------------------------------------------------------------------------
export class QueryCustomerValidations extends Query<getCustomerValidations> { }
The right solution can be a way to copy -and trigger- the <QueryCustomerValidations>element from the componentDidMount() method or, how to take the element away from the render() method and call it like with some sort of "await" way of doing it so it can be called first and the mutation after (and using the data from the query).
Thanks, I know this one is not really easy to figure out.
You're looking for 'old' (used before <Query/> component) HOC pattern (with compose) described here, here and here.
Composing "graphql(gqlquery ..." requested at start (without conditional skip option) with one or more (named) "gqlmutation ..." (called on demand) gives you a clear, readable solution.
compose(
graphql(Q_GET_CUSTOMER_VALIDATIONS),
graphql(gql`mutation { ... }`, { name: 'createSth' })
)(SomeComponent)
will pass data and createSth props to <SomeComponent/> then this.props.data object will contain loading, error and getCustomerValidations fields/properties. It's described here.
Query will be called at start (you can expect true in this.props.data.loading), no need to run query at cDM(). Mutation can be run using this.props.createSth() - custom name defined above (instead default prop name mutate).
Of course you can mix them with other required HOC's, f.e. redux connect(), withFormik() etc. - simply by adding single line of code.

Refetch container refetches, but does not update the view

My application looks something like what's included in the snippets below.
(I've left out a lot of the implementation details in the hopes that the code below is sufficient to get my question across).
SampleApp.js
const SampleAppQuery = graphql`
list SampleAppQuery {
...ItemComponent_item
}
`
function SampleApp() {
return (
<QueryRenderer
environment={environment}
query={SampleAppQuery}
render={(error, props) => {
if (props) {
return <AppRefetchContainer list={props} />
}
}}
/>
)
}
AppRefetchContainer.js
class AppRefetchContainer extends Component {
render() {
<div>
<HeaderComponent refetchList={this._refetchList} />
{list.map(item => <ItemComponent item={item} />)}
</div>
}
_refetchList(params) {
this.props.relay.refetch(params)
}
}
export default createRefetchContainer(
AppRefetchContainer,
graphql`
fragment AppRefetchContainer_list on Item {
...ItemComponent_item
}
`,
graphql`
query AppRefetchContainerQuery($sortBy: String!)
list SampleAppQuery(sortBy: $sortBy) {
...ItemComponent_item
}
`
)
The initial application load is just fine. Clicking on one of the headers should trigger a refetch so that the list data can be sorted on the passed inparams. When I trigger a refetch, the server responds with the correct data, however, the component does not rerender.
I suspect that my issue is with the way I've defined the fragments here. The console error I get on initial page load is:
RelayModernSelector: Expected object to contain data for fragment
`AppRefetchContainer_list`, got `{"list":[{"__fragments":
{"ItemComponent_item":{}},"__id":"[some_valid_id]","__fragmentOwner":null},{...
Question(s):
I'm not entirely sure how to interpret that error. Is it the reason why I'm unable to rerender the UI?
I know this approach may not be ideal, but how do I refetch from a component that isn't necessarily a fragment of the query?
Happy to provide any clarification or missing context :)

Meteor / React SSR and data withTracker

I am trying to devellop a SSR app using meteor and react. Everything went pretty fine until I got the following error message :
Warning: Did not expect server HTML to contain a <div> in <div>.
which is apparently due to a difference between the tree created on server and the one on client.
I have the following to get and then show the data :
class Index extends Component {
renderCategories() {
return this.props.categories.map((category) => {
return <div key={category._id}>{category.name}</div>
})
}
render() {
if(!this.props.ready){
return null
}
return (
<div className="index">
<div className="index__right">
{this.props.categories ? this.renderCategories() : <div></div>}
</div>
</div>
)
}
}
const mapStateToProps = state => ({ selectedIndex : state.selectedIndex });
const TrackerIndex = withTracker(() => {
let ready = true
if(Meteor.isClient){
let categoriesSub = Meteor.subscribe('categories');
ready = categoriesSub.ready();
}
return {
categories: Categories.find({}).fetch(),
ready
}
})(Index)
export default connect(mapStateToProps)(TrackerIndex);
What shows on the screen is actually what I expect (list of categories) and it comes properly from Server as seen in the source code. I think the problem is that on server side I have my collection, then I get nothing on client side, then mysubscription and data again, but I do not get how to manage this difference due to the SSR, ideas how I could solve this ?

Resources