composeWithTracker returns undefined arguments - meteor

This Meteor client code prints into is undefined to the console. It is expected to print the value of the info.description property passed to the composeWithTracker(composer)(Info) at the bottom of the code.
Where did I go wrong? Thanks
//--------------- carInfo.jsx ---------------
import React from 'react';
const renderWhenData = ( info ) => {
console.log( 'info is ' +info); //<<<<<<<<<<<<<<<<<<< undefined
if ( info ) {
return <span>{ info.description }</span>;
};
export let Info = ( { info } ) => (
<p>{ renderWhenData( info ) }</p>
);
//--------------- carClass.jsx ---------------
import React from 'react';
import ReactDOM from 'react-dom';
import { composeWithTracker } from 'react-komposer';
import { Info } from '../ui/carInfo.jsx';
const composer = (props, onData) => {
const subscription = Meteor.subscribe('vehicles');
if (subscription.ready()) {
const cars = Vehicles.findOne({name: 'Jack'}); //<<<<<<<<<<<<<<< document OK.
onData(null, { cars });
}
};
const Container = composeWithTracker(composer)(Info);
ReactDOM.render(<Container />, document.getElementById('react-info'));

Related

I have successfully implemented the redux-persist with next-redux-wrapper in next js

Im getting data from the external api and storing it in the reducer.And im using redux-persist to persist the state while navigating from one page to another.But i have made left the whiteList as an empty array but all the state are being persisted?Need help
import "../assets/css/style.scss";
import "owl.carousel/dist/assets/owl.carousel.css";
import "owl.carousel/dist/assets/owl.theme.default.css";
import Layout from "../component/Layout/Layout";
import { wrapper } from "../redux/store";
import { useEffect } from "react";
import { useStore } from "react-redux";
function MyApp({ Component, pageProps }) {
const store = useStore((store) => store);
useEffect(() => {
{
typeof document !== undefined
? require("bootstrap/dist/js/bootstrap.bundle")
: null;
}
}, []);
return (
<Layout>
<Component {...pageProps} />;
</Layout>
);
}
export default wrapper.withRedux(MyApp);
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import { composeWithDevTools } from "redux-devtools-extension";
import { persistStore, persistReducer } from "redux-persist";
import storage from "redux-persist/lib/storage";
import rootReducer from "./index";
import { createWrapper, HYDRATE } from "next-redux-wrapper";
const middleware = [thunk];
let initialState={}
// BINDING MIDDLEWARE
const bindMiddleware = (middleware) => {
if (process.env.NODE_ENV !== "production") {
return composeWithDevTools(applyMiddleware(...middleware));
}
return applyMiddleware(...middleware);
};
const makeStore = ({ isServer }) => {
if (isServer) {
//If it's on server side, create a store
return createStore(rootReducer,initialState, bindMiddleware(middleware));
} else {
//If it's on client side, create a store which will persis
const persistConfig = {
key: "root",
storage: storage,
whiteList: [],
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
const store = createStore(persistedReducer,initialState, bindMiddleware(middleware));
store.__persisitor = persistStore(store); // This creates a persistor object & push that
persisted object to .__persistor, so that we can avail the persistability feature
return store;
}
};
// export an assembled wrapper
export const wrapper = createWrapper(makeStore);
If you keep the whitelist an empty array then nothing will be persisted.
You have to put inside that string array the redux reducers values you want to be persisted.
Example:
const persistConfig = {
key: 'root',
storage: storage,
whiteList: ['cart', 'form', 'user'],
};

Typescript Warning for next-redux-wrapper regarding state not found and not assignable to types

Im using next-redux-wrapper and I get following 2 type errors. Anyone encounter this before and how do you solve it? All else, the code is working and i can see my state in my redux-devtools-extension. Thanks
import { useSelector } from "react-redux";
import Layout from "../components/Layout";
import { getProjects } from "../redux/actions/projectActions";
import { wrapper } from "../redux/store";
const Redux = () => {
// Warning 1: Property 'allProjects' does not exist on type 'DefaultRootState'.ts(2339)
const { projects } = useSelector((state) => state.allProjects);
console.log("res", projects);
return (
<Layout>
<h1>Redux</h1>
</Layout>
);
};
export const getServerSideProps =
// Warning 2: Type '({ req }: GetServerSidePropsContext<ParsedUrlQuery>) => Promise<void>' is not assignable to type 'GetServerSideProps<any, ParsedUrlQuery>'.
Type 'Promise<void>' is not assignable to type 'Promise<GetServerSidePropsResult<any>>'.
Type 'void' is not assignable to type 'GetServerSidePropsResult<any>'.ts(2322)
wrapper.getServerSideProps(
(store) =>
async ({ req }) => {
(await store.dispatch(getProjects(req))) as any;
}
);
export default Redux;
I did below and the ts warnings went away
I m not sure if it's correct though but so far seems ok
import { RootStateOrAny, useSelector } from "react-redux";
import Layout from "../components/Layout";
import { getProjects } from "../redux/actions/projectActions";
import { wrapper } from "../redux/store";
const Redux = () => {
const { projects } = useSelector(
(state: RootStateOrAny) => state.allProjects
);
console.log("res", projects);
return (
<Layout>
<h1>Redux</h1>
</Layout>
);
};
export const getServerSideProps = wrapper.getServerSideProps(
(store) =>
async ({ req }) => {
await store.dispatch(getProjects(req));
return {
props: {},
};
}
);
export default Redux;

Cannot find store in redux connect in a Jest Test

I am getting the following error while trying to setup a component in my jest test :
Invariant Violation: Could not find "store" in either the context or
props of "Connect(TestComponent)". Either wrap the root component in a
, or explicitly pass "store" as a prop to
"Connect(TestComponent)".
My test looks like this :
import React from 'react';
import { shallow } from 'enzyme';
import { Map } from 'immutable';
import { createStore } from 'redux';
import TestComponent from '../TestComponent ';
import { Provider } from 'react-redux';
describe('test ', () => {
test(' testing', () => {
const state = { blah: 1 };
const reducer = s => s; //dummy reducer
const store = createStore(reducer, state);
const component = (
<Provider store={store}>
<TestComponent />
</Provider>
);
const wrapper = shallow(component);
let json = wrapper.html();
expect(json).toMatchSnapshot();
});
});
and the component being tested looks like this :
import React, { Component } from 'react';
import { connect } from 'react-redux';
class TestComponent extends Component {
render = () => {};
}
function mapStateToProps(state) {
return { blah: state };
}
export default connect(
mapStateToProps,
null
)(TestComponent);
I'm not exactly sure what is wrong with this. It all looks kosher to me. When calling html() it cannot find the store.
Try making your wrapper component a function instead of variable:
export const testWrapper = Component => {
return (
<Provider store={store}>
{Component}
</Provider>
);
};
const wrapper = shallow(testWrapper(<TestComponent/>));
let json = wrapper.html();
expect(json).toMatchSnapshot();
Also I'd recommend looking into redux-mock-store for testing.
Here is the solution, you need to create mocked store and pass it to the component wrapped by connect function.
index.ts:
import React, { Component } from 'react';
import { connect } from 'react-redux';
interface ITestComponentProps {
blah: any;
store: any;
}
export class TestComponent extends Component<ITestComponentProps> {
constructor(props) {
super(props);
}
public render() {
return <div>{this.props.blah}</div>;
}
}
function mapStateToProps(state) {
return { blah: state };
}
export default connect(mapStateToProps)(TestComponent);
Unit test:
import React from 'react';
import { shallow } from 'enzyme';
import ConnectedTestComponent, { TestComponent } from './';
import configureMockStore from 'redux-mock-store';
const state = 1;
const mockStore = configureMockStore();
const store = mockStore(state);
describe('test', () => {
it('t1', () => {
const connetedTestComponentWrapper = shallow(<ConnectedTestComponent store={store} />);
const testComponentWrapper = connetedTestComponentWrapper.find(TestComponent);
expect(testComponentWrapper.prop('blah')).toBe(state);
expect(testComponentWrapper.html()).toMatchSnapshot();
});
});
Unit test result with 100% coverage:
PASS src/stackoverflow/57290601/index.spec.tsx
test
✓ t1 (54ms)
-----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.tsx | 100 | 100 | 100 | 100 | |
-----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 1 passed, 1 total
Time: 3.089s, estimated 5s
snapshot:
// Jest Snapshot v1
exports[`test t1 1`] = `"<div>1</div>"`;
Here is the completed demo: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/57290601

isssue with redux and apollo 2.x.x

How should I use redux with apollo 2.x.x beside graphql ?
I have this error
"configureStore.js:11 Uncaught TypeError: Cannot read property 'reducer' of undefined
at ./src/store/configureStore.js.exports.default"
and it seems to be related to the cache instanse of apollo
import React from "react";
import ReactDOM from "react-dom";
import AppRouter from "./routers/AppRouter";
import registerServiceWorker from "./registerServiceWorker";
// 1
import { ApolloProvider } from "react-apollo";
import { ApolloClient } from "apollo-client";
import { HttpLink } from "apollo-link-http";
import { InMemoryCache } from "apollo-cache-inmemory";
import { ApolloLink } from 'apollo-client-preset';
import {AUTH_TOKEN} from './lib/constants';
import configureStore from './store/configureStore';
import "./styles/App.css";
const httpLink = new HttpLink({ uri: "http://localhost:3000/graphql" });
const middlewareAuthLink = new ApolloLink((operation, forward) => {
const token = localStorage.getItem(AUTH_TOKEN);
const authorizationHeader = token ? `Bearer ${token}` : null
operation.setContext({
headers: {
authorization: authorizationHeader
}
})
return forward(operation)
})
const httpLinkWithAuthToken = middlewareAuthLink.concat(httpLink)
console.log("httpLink",httpLink);
console.log("httpLinkWithAuthToken",httpLinkWithAuthToken);
const store =configureStore();
export const client = new ApolloClient({
link: httpLinkWithAuthToken,
cache: new InMemoryCache()
});
const jsx = (
<ApolloProvider store={store} client={client}>
<AppRouter />
</ApolloProvider>
);
ReactDOM.render(jsx, document.getElementById("app"));
registerServiceWorker();
and the store in configured in this way :
import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
import {client} from "../app";
import thunk from "redux-thunk";
import { ApolloClient } from "apollo-client";
export default ()=>{
const store =createStore(
combineReducers({
// classes:classes ,
apollo:client.reducer(),
}),
{}, //initial state
compose(
applyMiddleware(client.middleware()),
thunk.withExtraArgument(client),
// If you are using the devToolsExtension, you can add it here also
(typeof window.__REDUX_DEVTOOLS_EXTENSION__ !== 'undefined') ? window.__REDUX_DEVTOOLS_EXTENSION__() : f => f,
)
);
return srore;
}

A valid React element (or null) must be returned

This Meteor React code is producing browser console error:
Warning: ListItems(...): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.
Exception from Tracker recompute function:
Any idea why? Thanks
//myList.jsx
import React from 'react';
const renderIfData = (listItems) => {
if (listItems && listItems.length > 0) {
return listItems.map((item) => {
return <li key={item._id}>{item.car}</li>;
});
} else {
return <p> No cars yet!</p>
}
};
export const ListItems = ({listItems}) => {
<ol>{renderIfData(listItems)}</ol>
};
//cars.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import { composeWithTracker } from 'react-komposer';
import { ListItems } from '../imports/ui/myList.jsx';
import { CarsCol } from '../imports/api/collections.js';
const composer = (props, onData) => {
const sub = Meteor.subscribe('carsCol');
if (sub.ready()) {
const cars = CarsCol.find().fetch();
onData(null, {cars});
}
};
const Container = composeWithTracker(composer) (ListItems);
ReactDOM.render(<Container />, document.getElementById('react-root'));
Everything looks nice except this part:
return listItems.map((item) => {
return <li key={item._id}>{item.car}</li>;
});
The result of this operation is an array of elements, and React discourages it with exactly the kind of error you're receiving. In fact, in React 16, they promise to allow this, but you're likely using version 15. Anyway, I'd recommend returning a single root element everywhere, so the whole thing would look like
//myList.jsx
import React from 'react';
export const ListItems = ({listItems}) => {
if (listItems && listItems.length > 0) {
return (
<ol>
{listItems.map((item) => (
<li key={item._id}>{item.car}</li>
))}
</ol>
);
} else {
return (
<p>No cars yet!</p>
);
}
};
//cars.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import { composeWithTracker } from 'react-komposer';
import { ListItems } from '../imports/ui/myList.jsx';
import { CarsCol } from '../imports/api/collections.js';
const composer = (props, onData) => {
const sub = Meteor.subscribe('carsCol');
if (sub.ready()) {
const cars = CarsCol.find().fetch();
onData(null, {cars});
}
};
const Container = composeWithTracker(composer) (ListItems);
ReactDOM.render(<Container />, document.getElementById('react-root'));

Resources