I am still not as fluent in ReactJS, Ant Design, Sagas and Reducers as I thought I am: I am trying to maintain/ debug a single-page app and I am not sure which files I have to adjust and how.
The goal is to add the following <select> in their render() function within component.tsx:
<Select showSearch
style={{ width: 150 }}
placeholder="Select entity"
// onChange={(e) => { this.handleSelectorChange("Entity", e) }} // to tackle later
// value={this.props.selectedEntity.toString()} // ------ " ------
>
<Option value="0">Option 0</Option>
{this.props.availableEntities.map((myEntity) =>
(<Option key={myEntity.Id.toString()}
value={myEntity.Id.toString()}>{myEntity.Name}</Option>))}
</Select>
In the respective container.tsx, I added:
const mapStateToProps = (state ) => ({
availableEntities: GeneralSelectors.getAvailableEntities(state),
});
What I get back is the following is only Option 0 instead of all entities (and even on a wrong place), see screenshot
How do I get my selection options dynamically generated using data from an API? Since I do not see backend being called (using the Network tab of my Chrome debugger), I assume something is wrong with the sagas, but that is just an hypothesis.
Background info
For another single-page-app (SPA) of the same project which already has that <select> inside, I found a urls.ts which looks as follows
import UrlMap from "../UrlMap"
import * as Actions from "./actions"
import * as GeneralActions from "../general/actions"
export const urls = [
new UrlMap("myWorkingSPA",
() => [
Actions.load(),
GeneralActions.loadEntities(),
Actions.loadDifferencePositions()
])
];
I don't know where this file is actually called, and what I have to modify where in order to include it.
In the respective actions.ts of the running SPA I find
export function loadEntities() : Action {
return {
type: LOAD_ENTITIES
}
}
I am not sure whether my SPA is also taking this actions.ts or not.
The sagas.ts is the same for the running SPA and for my component:
function* loadEntities() {
const url = config.apiBaseUrl + "/api/Entities";
try {
const response: Response = yield fetch(url);
const json: Interfaces.Entity[] = yield response.json();
yield put(Actions.setEntities(json));
} catch (e) {
notification.error({ message: "Error", description: "Error loading Entities" });
}
}
function* watchLoadEntities() {
yield takeEvery(Actions.LOAD_ENTITIES, loadEntities);
}
Hope that was not too much information, but I guess it is all related to the problem.
References
populate select option in reactjs
Mapping checkboxes inside checkboxes ReactJS
Eventually I also found another sagas.ts which was also in effect:
function* parseUrl({ payload }) {
const pathName = payload.location.pathname;
const myComponentURI: match<{}> = matchPath(pathName, { path: config.uiBaseUrl + "myComponent" });
if (myComponentURI) {
yield put(GeneralActions.loadEntities()); // <---
}
// ... here are many more const. for various different pages
}
The GeneralActions refers to an actions.ts in a directory general.
I solved the issue by putting the marked line. Warning: I believe, this is not the way things should be implemented, I am just saying that it hot-fixed my issue.
As clafou pointed out in a comment, the clean way would be to trigger the yield on startup.
Related
I am using vim to code, namely in javascript. I would love to be able to auto-indent javascript code. My main use case is being able to automatically jump from a one-liner javascript code to a fully indented pretty-printed code (just as https://beautifier.io/ would do).
Despite looking for help on google and SO, I was not able to find any auto-indent related question in the specific case where code to indent is a one-liner.
Sample input file :
import { BASE_URL } from "#/constants/config"; import { request } from "#/utils/request"; export const FOOTER_ENDPOINTS = { links: `${ BASE_URL} api/footer/links/`, } ; class Footer { async fetchLinks() { const { data } = await request({ url: FOOTER_ENDPOINTS.links, }); return data; } } export const FooterService = new Footer();
I am expecting the following output :
import { BASE_URL } from "#/constants/config";
import { request } from "#/utils/request";
export const FOOTER_ENDPOINTS = {
links: `${BASE_URL}api/footer/links/`,
};
class Footer {
async fetchLinks() {
const { data } = await request({
url: FOOTER_ENDPOINTS.links,
});
return data;
}
}
export const FooterService = new Footer();
So far i have unsuccessfully tried =G and gg=G commands, as well as :Autoformat from vim-autoformat plugin and pangloss/vim-javascript plugin.
Best hint I have is to use maksimr/vim-jsbeautify but the result is not as "pretty printed" as I would have expected. Maybe some editorconfig properties I do not know might help for adding line breaks and avoid imports being breaked when not too long ?
import {
BASE_URL
} from "#/constants/config";
import {
request
} from "#/utils/request";
export const FOOTER_ENDPOINTS = {
links: `${BASE_URL}api/footer/links/`,
};
class Footer {
async fetchLinks() {
const {
data
} = await request({
url: FOOTER_ENDPOINTS.links,
});
return data;
}
}
export const FooterService = new Footer();
BONUS : I would be amazing if the solution could also auto-indent dict-like entities such as javascript or json for instance.
Being the generalist text editor that it is, there is a limit to what Vim can do on its own with specific filetypes.
Out of the box, Vim is incapable of doing what you ask but it allows you to use external tools that do.
What you need to figure out is:
what external tool to use,
how to configure it to get the desired outcome,
how to integrate it with Vim.
js-beautify
The web app you mention uses js-beautify so, if you are happy with how the web app formats your code, then you should give js-beautify a try.
The first problem, here, is that the web app doesn't actually format your sample the way you claim it does. It outputs this:
import {
BASE_URL
} from "#/constants/config";
import {
request
} from "#/utils/request";
export const FOOTER_ENDPOINTS = {
links: `${ BASE_URL} api/footer/links/`,
};
class Footer {
async fetchLinks() {
const {
data
} = await request({
url: FOOTER_ENDPOINTS.links,
});
return data;
}
}
export const FooterService = new Footer();
which happens to be identical to what local js-beautify outputs by default.
If that web app is really able to format your code the way you want, then you must try various settings until you are satisfied and then move on to the configuration phase.
But there is a second problem: I just spent a few minutes playing with the settings and I'm afraid I have to point out that this statement:
just as https://beautifier.io/ would do
is patently false. The web app can't do your ideal formatting and the underlying js-beautify is very likely to be similarly limited.
So you are back to step #1: figuring out what external tool to useā¦ which is outside of the scope of this site.
I'm trying to deploy my first next.js project on vercel. Locally everything is working.
My problem: When deploying (command: next build) the web app I get the message "Generating static sites (0/2000)" and then nothing happens. The deployment is cancelled after 1h (time expiration).
The problem is somewhere in the (simplified) code below. Here's why: when I deploy the project without the part that follows after const content the deployment is successful - so basically instead of having singleProductResponse AND contentResponse as props, I only have singleProductResponse..
I'm a little stuck and don't know how to solve this. Can someone tell me what I'm doing wrong? Thanks a lot!!
const Item = ({ singleProductResponse, contentResponse }) => {
const router = useRouter();
if (router.isFallback) {
return <div>Loading...</div>;
}
return (
<div className={styles.section}>
<Overview
singleProductResponse={singleProductResponse}
contentResponse={contentResponse}
/>
</div>
);
};
export async function getStaticPaths() {
const itemResponse = await knex("Items");
const paths = itemResponse.map((product) => ({
params: {
brand: product.brand,
item: product.item,
},
}));
return {
paths,
fallback: true,
};
}
export async function getStaticProps({ params }) {
try {
const itemData = await knex("Items").where(
"item",
"like",
`${params.item}`
);
const singleProductResponse = itemData[0];
//!!!!!!!!!when leaving the following part out: deployment is successful!!!!!!!!!!!!
const content = itemData[0].contentList;
const splitContent = content.split(", ");
const contentArray =
typeof splitContent === "string"
? [splitContent]
: splitContent;
const result = await knex("Cos")
.leftJoin("Actives", "Cos.content", "ilike", "Actives.content")
.leftJoin("Alcohol", "Cos.content", "ilike", "Alcohol.content")
.column([
"Cos.content",
"function",
"translationPlant",
"categoryAlcohol",
])
.where((qb) => {
contentArray.forEach((word) => {
qb.orWhere("Cos.content", word);
});
return qb;
});
return {
props: { singleProductResponse, contentResponse },
revalidate: 1,
};
} catch (err) {
console.log(err);
return {
redirect: {
destination: "/",
permanent: false,
},
};
}
}
UPDATE
After digging deeper: I think the problem is that the part after const content is too slow in building process.
When running next build, as well as when deploying on vercel the building process stops after approx. 1h. I suppose this is because of the limit of 45min for building process.
The last message I get is "Generating static pages (1000/2000)" (in vercel and locally) and "Build failed" (vercel). I don't get any other error-messages (also not in the catch block).
I've already tried to optimize the part after const content (each table has an index (clustered indexes -> primary keys), I've redesigned the tables (only 4 tables to join, instead of 6), eliminated everything unnecessary in the query and checked that the database (postgres hosted on heroku - hobby-basic) is also in the US). The performance is better, but still not enough. Does anyone have some suggestions for improvement? TTFB might be a somehow slow.
I'm starting with Next.js and after going through docs, I cannot figure out how to get the route param code inside getStaticPaths method as shown below!?. code is not known before hand by any means and it can be anything.
I don't want to call api and get the data using useEffect inside the component.
File: pages/post/[code].js
import React from 'react';
import apiCall from 'api/something';
export default ({post}) => {
return <>
render components here based on prop `post`
</>
}
export async function getStaticPaths() {
// How to get [code] from the route here, which can be used below?
return {
paths: // NEED [code] HERE from current route,
fallback: false
}
}
export async function getStaticProps(ctx) {
return {
props: {
// [ctx.code] resolved from current route with the help of getStaticPaths,
post: apiCall(ctx.code)
}
}
}
I've tried getServerSideProps which works for me:
export const getServerSideProps = async (ctx) => {
return {
props: {
post: await apiCall(ctx.query.code)
}
};
};
But it fails when I do next export stating:
pages with getServerSideProps can not be exported. See more info here: https://err.sh/next.js/gssp-export
After investigating further on this error I found this solution, which is not feasible for me as my app is hosted on Heroku.
I'm trying to server-side render the html along with the data based on the route param code. But not able to do so now.
The purpose of the function getStaticPaths is to generate a list of paths for which static HTML will be rendered at build time. For example, for a list of 10 posts, you can generate 10 posts/[id] routes ahead of time if you know the id of the posts.
How getStaticPaths works with dynamic routes in more details..
Suppose you have a dynamic route /posts/[postId] if you choose to use static-generation you have to generate a list of paths that will include the postId as a route param and for each path returned, the function getStaticProps will be called to query the data at build time. Example,
// for /post/[postId]
export const getStaticPaths = async () => {
// if you know all the postId ahead of time
const paths = [
{ params: { postId: '1234' } }, // keep in mind postId has to be a string
{ params: { postId: '3792' } },
{ params: { postId: '1749' } },
]
return {
paths,
fallback: false // we are disabling fallback because we know all the paths ahead of time
}
}
// for each path returned getStaticProps will be called at build time
export const getStaticProps = async (context) => {
// you have access to the postId params that you returns from
// getStaticPaths here
const postId = context.params.postId
// now you can query the data from postId and return as props
return {
props: // queried data
}
}
If fallback is set to false any for any route path that is not returned from the function getStaticPaths nextjs will simply show a 404 error page.
How to use fallback: true to generate static pages for route params not known ahead of time
If you know some postId of the posts and the data for the posts do not change very often, you can choose to generate the pages with fallback property set to true, which will display a fallback version of the page for the paths that are not returned from the function getStaticPaths. And on request for the page nextjs will call getStaticProps and send the data as JSON which will be used to render the page in the browser.
Example,
// for /post/[postId]
export const getStaticPaths = async () => {
// you can get how many ever postIds are know ahead of time
// and return as paths with fallback set to true
const posts = // queried data from db or fetched from remote API
const paths = posts.map(post => { params:{ postId: post.id.toString() }})
return {
paths,
fallback: true
}
}
// in your page Component check for fallback and render a loading indicator
import { useRouter } from 'next/router';
const MyPage = (props) => {
// before you do anything
const router = useRouter();
if (router.isFallback) {
return <div>Loading....</div>
}
// rest of your page logic
}
If your data is very dynamic, let's say changing every 30mins or an hour or so. You can choose to use server-side rendering which will fetch the data on per request basis, but TTFB(time to first byte) will be higher. For example,
// for /post/[postId]
export const getServerSideProps = async (context) => {
// you also have access to the param postId from the context
const postId = context.params.postId
// query the data based on the postId and return as props
return {
props: // queried data
}
}
Keep in mind if you choose to go with getServerSideProps the function will be called on per-request basis so time to first byte will be higher.
Depending on use-cases you can also use static generation with client-side data fetching using swr from nextjs team repo link.
As I understand, you want to statically generate dynamic routes at build time.
To do so you need to let Next.js know what pages to generate, by specifying all codes.
export async function getStaticPaths() {
// you don't need here a code from current route
// but you need to specify all known post codes
return {
paths: [
{ params: { code: '1' } },
{ params: { code: '2' } },
{ params: { code: '3' } },
]
fallback: false
}
}
You would need to re-build app every time you change the posts.
Use getServerSideProps if you don't want to re-build project every time. Then the data would be fetched at request time. You can't export it because it requires Node.js server.
Given the following function:
./http.js
const http = {
refetch() {
return (component) => component;
}
}
I would like to mock the function in a test as follows:
./__tests__/someTest.js
import { refetch } from './http';
jest.mock('./http', () => {
return {
refetch: jest.fn();
}
}
refetch.mockImplementation((component) => {
// doing some stuff
})
But I'm receiving the error
TypeError: _http.refetch.mockImplementation is not a function
How can I mock the refetch function in the given example?
update:
When I modify the mock function slightly to:
jest.mock(
'../http',
() => ({ refetch: jest.fn() }),
);
I get a different error:
TypeError: (0 , _http.refetch)(...) is not a function
My guess it's something with the syntax where the curried function (or HOC function) is not mapped properly. But I don't know how to solve it.
Some of the real code I'm trying to test.
Note: The example is a bit sloppy. It works in the application. The example given is to give an idea of the workings.
./SettingsContainer
// ...some code
return (
<FormComponent
settingsFetch={settingsFetch}
settingsPutResponse={settingsPutResponse}
/>
);
}
const ConnectedSettingsContainer = refetch(
({
match: { params: { someId } },
}) => ({
settingsFetch: {
url: 'https://some-url.com/api/v1/f',
},
settingsPut: (data) => ({
settingsPutResponse: {
url: 'https://some-url.com/api/v1/p',
}
}),
}),
)(SettingsContainer);
export default ConnectedSettingsContainer;
Then in my component I am getting the settingsPutResponse via the props which react-refetch does.
I want to test if the user can re-submit a form after the server has responded once or twice with a 500 until a 204 is given back.
./FormComponent
// ...code
const FormComp = ({ settingsResponse }) => {
const [success, setSuccess] = useState(false);
useEffect(() => {
if (settingsResponse && settingsResponse.fulfilled) {
setSuccess(true);
}
}, [settingsResponse]);
if (success) {
// state of the form wil be reset
}
return (
<form>
<label htmlFor"username">
<input type="text" id="username" />
<button type="submit">Save</button>
</form>
)
};
The first question to ask yourself about mocking is "do I really need to mock this?" The most straightforward solution here is to test "component" directly instead of trying to fake out an http HOC wrapper around it.
I generally avoid trying to unit test things related to I/O. Those things are best handled with functional or integration tests. You can accomplish that by making sure that, given same props, component always renders the same output. Then, it becomes trivial to unit test component with no mocks required.
Then use functional and/or integration tests to ensure that the actual http I/O happens correctly
To more directly answer you question though, jest.fn is not a component, but React is expecting one. If you want the mock to work, you must give it a real component.
Your sample code here doesn't make sense because every part of your example is fake code. Which real code are you trying to test? I've seen gigantic test files that never actually exercize any real code - they were just testing an elaborate system of mocks. Be careful not to fall into that trap.
I am new to React Native, please provide some Github link or your own code for reference. Consider me as a beginner in RN.
I found very less open support for RN, Mobx State tree, Ignite and all, so not just post and get API reference, if you find anything helpful related to these above-mentioned topics, Feel free to share.
Thanks in advance.
Mobx State Tree, With Ignite Bowler you would have api.ts file where you can specify API calls.
async getUser(userToken: string): Promise<Types.GetUserResult> {
// make the api call
const response: ApiResponse<any> = await this.apisauce.post(`api/v1/sales/login?authCode=${userToken}`)
if (!response.ok) {
const problem = getGeneralApiProblem(response)
if (problem) return problem
}
// transform the data into the format we are expecting
try {
try {
const rawUser = response.data
console.log('rawUser'+ rawUser)
const user: UserSnapshot = convertRawUserToUserStore(rawUser)
return { kind: "ok", user }
console.log({ user })
} catch (e) {
__DEV__ && console.tron.log(e.message)
return { kind: "bad-data" }
}
} catch {
return { kind: "bad-data" }
}
}
Consider, we will be getting user data from this API call,
you can notice that there is UserSnapshot which belongs to User Model, Snapshot will save the data automatically, you don't need Aysnc storage to save or retrieve data.