Skip to content

Commit a9072d2

Browse files
committed
Merge branch 'master' of https://github.com/reduxjs/redux-templates into add-expo-ts-template
2 parents 71f4b98 + ffdfdf7 commit a9072d2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+29991
-33042
lines changed

packages/cra-template-redux-typescript/package-lock.json

Lines changed: 11534 additions & 20228 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/cra-template-redux-typescript/package.json

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -34,32 +34,33 @@
3434
"template.json"
3535
],
3636
"devDependencies": {
37-
"@babel/preset-env": "^7.16.11",
38-
"@babel/preset-react": "^7.16.7",
39-
"@reduxjs/toolkit": "^1.8.1",
40-
"@testing-library/jest-dom": "^5.16.4",
41-
"@testing-library/react": "^13.1.1",
42-
"@types/jest": "^27.4.1",
43-
"@types/node": "^17.0.25",
44-
"@types/react": "^18.0.6",
45-
"@types/react-dom": "^18.0.2",
37+
"@babel/preset-env": "^7.23.8",
38+
"@babel/preset-react": "^7.23.3",
39+
"@reduxjs/toolkit": "^2.0.1",
40+
"@testing-library/jest-dom": "^6.2.0",
41+
"@testing-library/react": "^14.1.2",
42+
"@testing-library/user-event": "^14.5.2",
43+
"@types/jest": "^29.5.11",
44+
"@types/node": "^20.11.0",
45+
"@types/react": "^18.2.47",
46+
"@types/react-dom": "^18.2.18",
4647
"babel-eslint": "^10.1.0",
47-
"babel-jest": "^27.5.1",
48-
"eslint": "^8.14.0",
48+
"babel-jest": "^29.7.0",
49+
"eslint": "^8.56.0",
4950
"eslint-config-react-app": "^7.0.1",
50-
"eslint-plugin-import": "^2.26.0",
51-
"eslint-plugin-jsx-a11y": "^6.5.1",
52-
"eslint-plugin-prettier": "^4.0.0",
53-
"eslint-plugin-react": "^7.29.4",
54-
"eslint-plugin-react-hooks": "^4.4.0",
55-
"jest": "^27.5.1",
56-
"prettier": "^2.6.2",
57-
"react": "^18.0.0",
58-
"react-dom": "^18.0.0",
59-
"react-redux": "^8.0.1",
51+
"eslint-plugin-import": "^2.29.1",
52+
"eslint-plugin-jsx-a11y": "^6.8.0",
53+
"eslint-plugin-prettier": "^5.1.3",
54+
"eslint-plugin-react": "^7.33.2",
55+
"eslint-plugin-react-hooks": "^4.6.0",
56+
"jest": "^29.7.0",
57+
"prettier": "^3.2.1",
58+
"react": "^18.2.0",
59+
"react-dom": "^18.2.0",
60+
"react-redux": "^9.1.0",
6061
"react-scripts": "^5.0.1",
61-
"react-test-renderer": "^18.0.0",
62-
"typescript": "^4.6",
63-
"web-vitals": "^2.1.0"
62+
"react-test-renderer": "^18.2.0",
63+
"typescript": "^5.3",
64+
"web-vitals": "^3.5.1"
6465
}
6566
}
Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,27 @@
11
{
22
"package": {
33
"dependencies": {
4-
"@reduxjs/toolkit": "^1.8.1",
5-
"@testing-library/jest-dom": "^5.16.4",
6-
"@testing-library/react": "^13.0.1",
7-
"@testing-library/user-event": "^14.1.1",
8-
"@types/jest": "^27.4.1",
9-
"@types/node": "^17.0.25",
10-
"@types/react": "^18.0.6",
11-
"@types/react-dom": "^18.0.2",
12-
"react-redux": "^8.0.1",
13-
"typescript": "^4.6.0",
14-
"web-vitals": "^2.1.0"
4+
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
5+
"@reduxjs/toolkit": "^2.0.1",
6+
"@testing-library/jest-dom": "^6.2.0",
7+
"@testing-library/react": "^14.1.2",
8+
"@testing-library/user-event": "^14.5.2",
9+
"@types/jest": "^29.5.11",
10+
"@types/node": "^20.11.0",
11+
"@types/react": "^18.2.47",
12+
"@types/react-dom": "^18.2.18",
13+
"eslint": "^8.56.0",
14+
"eslint-config-prettier": "^9.1.0",
15+
"prettier": "^3.2.1",
16+
"react-redux": "^9.1.0",
17+
"typescript": "^5.3.3",
18+
"web-vitals": "^3.5.1"
1519
},
16-
"eslintConfig": {
17-
"extends": ["react-app", "react-app/jest"]
20+
"scripts": {
21+
"format": "prettier --write .",
22+
"lint": "eslint .",
23+
"lint:fix": "eslint --fix .",
24+
"type-check": "tsc"
1825
}
1926
}
2027
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"extends": [
3+
"eslint:recommended",
4+
"react-app",
5+
"plugin:react/jsx-runtime",
6+
"prettier"
7+
],
8+
"parser": "@typescript-eslint/parser",
9+
"parserOptions": { "project": true, "tsconfigRootDir": "./" },
10+
"plugins": ["@typescript-eslint"],
11+
"root": true,
12+
"ignorePatterns": ["build"],
13+
"rules": {
14+
"@typescript-eslint/consistent-type-imports": [
15+
2,
16+
{ "fixStyle": "separate-type-imports" }
17+
],
18+
"@typescript-eslint/no-restricted-imports": [
19+
2,
20+
{
21+
"paths": [
22+
{
23+
"name": "react-redux",
24+
"importNames": ["useSelector", "useStore", "useDispatch"],
25+
"message": "Please use pre-typed versions from `src/app/hooks.ts` instead."
26+
}
27+
]
28+
}
29+
]
30+
},
31+
"overrides": [
32+
{ "files": ["*.{c,m,}{t,j}s", "*.{t,j}sx"] },
33+
{ "files": ["*{test,spec}.{t,j}s?(x)"], "env": { "jest": true } }
34+
]
35+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"arrowParens": "avoid",
3+
"semi": false
4+
}

packages/cra-template-redux-typescript/template/public/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!DOCTYPE html>
1+
<!doctype html>
22
<html lang="en">
33
<head>
44
<meta charset="utf-8" />
Lines changed: 105 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,105 @@
1-
import React from 'react';
2-
import { render } from '@testing-library/react';
3-
import { Provider } from 'react-redux';
4-
import { store } from './app/store';
5-
import App from './App';
6-
7-
test('renders learn react link', () => {
8-
const { getByText } = render(
9-
<Provider store={store}>
10-
<App />
11-
</Provider>
12-
);
13-
14-
expect(getByText(/learn/i)).toBeInTheDocument();
15-
});
1+
import { screen, waitFor } from "@testing-library/react"
2+
import App from "./App"
3+
import { renderWithProviders } from "./utils/test-utils"
4+
5+
test("App should have correct initial render", () => {
6+
renderWithProviders(<App />)
7+
8+
// The app should be rendered correctly
9+
expect(screen.getByText(/learn/i)).toBeInTheDocument()
10+
11+
// Initial state: count should be 0, incrementValue should be 2
12+
expect(screen.getByLabelText("Count")).toHaveTextContent("0")
13+
expect(screen.getByLabelText("Set increment amount")).toHaveValue(2)
14+
})
15+
16+
test("Increment value and Decrement value should work as expected", async () => {
17+
const { user } = renderWithProviders(<App />)
18+
19+
// Click on "+" => Count should be 1
20+
await user.click(screen.getByLabelText("Increment value"))
21+
expect(screen.getByLabelText("Count")).toHaveTextContent("1")
22+
23+
// Click on "-" => Count should be 0
24+
await user.click(screen.getByLabelText("Decrement value"))
25+
expect(screen.getByLabelText("Count")).toHaveTextContent("0")
26+
})
27+
28+
test("Add Amount should work as expected", async () => {
29+
const { user } = renderWithProviders(<App />)
30+
31+
// "Add Amount" button is clicked => Count should be 2
32+
await user.click(screen.getByText("Add Amount"))
33+
expect(screen.getByLabelText("Count")).toHaveTextContent("2")
34+
35+
const incrementValueInput = screen.getByLabelText("Set increment amount")
36+
// incrementValue is 2, click on "Add Amount" => Count should be 4
37+
await user.clear(incrementValueInput)
38+
await user.type(incrementValueInput, "2")
39+
await user.click(screen.getByText("Add Amount"))
40+
expect(screen.getByLabelText("Count")).toHaveTextContent("4")
41+
42+
// [Negative number] incrementValue is -1, click on "Add Amount" => Count should be 3
43+
await user.clear(incrementValueInput)
44+
await user.type(incrementValueInput, "-1")
45+
await user.click(screen.getByText("Add Amount"))
46+
expect(screen.getByLabelText("Count")).toHaveTextContent("3")
47+
})
48+
49+
it("Add Async should work as expected", async () => {
50+
const { user } = renderWithProviders(<App />)
51+
52+
// "Add Async" button is clicked => Count should be 2
53+
await user.click(screen.getByText("Add Async"))
54+
55+
await waitFor(() =>
56+
expect(screen.getByLabelText("Count")).toHaveTextContent("2"),
57+
)
58+
59+
const incrementValueInput = screen.getByLabelText("Set increment amount")
60+
// incrementValue is 2, click on "Add Async" => Count should be 4
61+
await user.clear(incrementValueInput)
62+
await user.type(incrementValueInput, "2")
63+
64+
await user.click(screen.getByText("Add Async"))
65+
await waitFor(() =>
66+
expect(screen.getByLabelText("Count")).toHaveTextContent("4"),
67+
)
68+
69+
// [Negative number] incrementValue is -1, click on "Add Async" => Count should be 3
70+
await user.clear(incrementValueInput)
71+
await user.type(incrementValueInput, "-1")
72+
await user.click(screen.getByText("Add Async"))
73+
await waitFor(() =>
74+
expect(screen.getByLabelText("Count")).toHaveTextContent("3"),
75+
)
76+
})
77+
78+
test("Add If Odd should work as expected", async () => {
79+
const { user } = renderWithProviders(<App />)
80+
81+
// "Add If Odd" button is clicked => Count should stay 0
82+
await user.click(screen.getByText("Add If Odd"))
83+
expect(screen.getByLabelText("Count")).toHaveTextContent("0")
84+
85+
// Click on "+" => Count should be updated to 1
86+
await user.click(screen.getByLabelText("Increment value"))
87+
expect(screen.getByLabelText("Count")).toHaveTextContent("1")
88+
89+
// "Add If Odd" button is clicked => Count should be updated to 3
90+
await user.click(screen.getByText("Add If Odd"))
91+
expect(screen.getByLabelText("Count")).toHaveTextContent("3")
92+
93+
const incrementValueInput = screen.getByLabelText("Set increment amount")
94+
// incrementValue is 1, click on "Add If Odd" => Count should be updated to 4
95+
await user.clear(incrementValueInput)
96+
await user.type(incrementValueInput, "1")
97+
await user.click(screen.getByText("Add If Odd"))
98+
expect(screen.getByLabelText("Count")).toHaveTextContent("4")
99+
100+
// click on "Add If Odd" => Count should stay 4
101+
await user.clear(incrementValueInput)
102+
await user.type(incrementValueInput, "-1")
103+
await user.click(screen.getByText("Add If Odd"))
104+
expect(screen.getByLabelText("Count")).toHaveTextContent("4")
105+
})
Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import React from 'react';
2-
import logo from './logo.svg';
3-
import { Counter } from './features/counter/Counter';
4-
import './App.css';
1+
import "./App.css"
2+
import { Counter } from "./features/counter/Counter"
3+
import { Quotes } from "./features/quotes/Quotes"
4+
import logo from "./logo.svg"
55

6-
function App() {
6+
const App = () => {
77
return (
88
<div className="App">
99
<header className="App-header">
@@ -12,11 +12,12 @@ function App() {
1212
<p>
1313
Edit <code>src/App.tsx</code> and save to reload.
1414
</p>
15+
<Quotes />
1516
<span>
1617
<span>Learn </span>
1718
<a
1819
className="App-link"
19-
href="https://reactjs.org/"
20+
href="https://reactjs.org"
2021
target="_blank"
2122
rel="noopener noreferrer"
2223
>
@@ -25,7 +26,7 @@ function App() {
2526
<span>, </span>
2627
<a
2728
className="App-link"
28-
href="https://redux.js.org/"
29+
href="https://redux.js.org"
2930
target="_blank"
3031
rel="noopener noreferrer"
3132
>
@@ -34,25 +35,34 @@ function App() {
3435
<span>, </span>
3536
<a
3637
className="App-link"
37-
href="https://redux-toolkit.js.org/"
38+
href="https://redux-toolkit.js.org"
3839
target="_blank"
3940
rel="noopener noreferrer"
4041
>
4142
Redux Toolkit
4243
</a>
43-
,<span> and </span>
44+
<span>, </span>
4445
<a
4546
className="App-link"
46-
href="https://react-redux.js.org/"
47+
href="https://react-redux.js.org"
4748
target="_blank"
4849
rel="noopener noreferrer"
4950
>
5051
React Redux
5152
</a>
53+
,<span> and </span>
54+
<a
55+
className="App-link"
56+
href="https://reselect.js.org"
57+
target="_blank"
58+
rel="noopener noreferrer"
59+
>
60+
Reselect
61+
</a>
5262
</span>
5363
</header>
5464
</div>
55-
);
65+
)
5666
}
5767

58-
export default App;
68+
export default App
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { asyncThunkCreator, buildCreateSlice } from "@reduxjs/toolkit"
2+
3+
// `buildCreateSlice` allows us to create a slice with async thunks.
4+
export const createAppSlice = buildCreateSlice({
5+
creators: { asyncThunk: asyncThunkCreator },
6+
})
Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1-
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
2-
import type { RootState, AppDispatch } from './store';
1+
// This file serves as a central hub for re-exporting pre-typed Redux hooks.
2+
// These imports are restricted elsewhere to ensure consistent
3+
// usage of typed hooks throughout the application.
4+
// We disable the ESLint rule here because this is the designated place
5+
// for importing and re-exporting the typed versions of hooks.
6+
/* eslint-disable @typescript-eslint/no-restricted-imports */
7+
import { useDispatch, useSelector } from "react-redux"
8+
import type { AppDispatch, RootState } from "./store"
39

410
// Use throughout your app instead of plain `useDispatch` and `useSelector`
5-
export const useAppDispatch: () => AppDispatch = useDispatch;
6-
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
11+
export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
12+
export const useAppSelector = useSelector.withTypes<RootState>()

0 commit comments

Comments
 (0)