Skip to content

Commit e705838

Browse files
committed
feat: react-context-reducer
1 parent 5f2d4c2 commit e705838

File tree

11 files changed

+219
-0
lines changed

11 files changed

+219
-0
lines changed

README.md

+5
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@
5252
<td><a href="./packages/react-mobx-redux">packages/react-mobx-redux</a></td>
5353
</tr>
5454

55+
<tr>
56+
<td><a href="https://juejin.cn/post/7265516410490880035">Context与Reducer</a></td>
57+
<td><a href="./packages/react-context-reducer">packages/react-context-reducer</a></td>
58+
</tr>
59+
5560
<tr>
5661
<td><a href="https://juejin.cn/post/7276990690546270247">ReactPortals传送门</a></td>
5762
<td><a href="./packages/react-portals">packages/react-portals</a></td>

packages/react-context-reducer/.env

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
BROWSER=none
2+
PUBLIC_URL=.
3+
DISABLE_ESLINT_PLUGIN=true
4+
GENERATE_SOURCEMAP=false
5+
TSC_COMPILE_ON_ERROR=true
6+
TSC_WATCHFILE=UseFsEventsWithFallbackDynamicPolling
7+
SKIP_PREFLIGHT_CHECK=true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "react-context-reducer",
3+
"version": "1.0.0",
4+
"description": "",
5+
"keywords": [],
6+
"main": "src/index.tsx",
7+
"dependencies": {
8+
"react": "17.0.2",
9+
"react-dom": "17.0.2",
10+
"react-scripts": "4.0.3"
11+
},
12+
"devDependencies": {
13+
"@types/react": "17.0.20",
14+
"@types/react-dom": "17.0.9"
15+
},
16+
"scripts": {
17+
"dev": "react-scripts start",
18+
"build": "react-scripts build",
19+
"test": "react-scripts test --env=jsdom",
20+
"eject": "react-scripts eject"
21+
},
22+
"browserslist": [
23+
">0.2%",
24+
"not dead",
25+
"not ie <= 11",
26+
"not op_mini all"
27+
]
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="utf-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
7+
<meta name="theme-color" content="#000000">
8+
<!--
9+
manifest.json provides metadata used when your web app is added to the
10+
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
11+
-->
12+
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
13+
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
14+
<!--
15+
Notice the use of %PUBLIC_URL% in the tags above.
16+
It will be replaced with the URL of the `public` folder during the build.
17+
Only files inside the `public` folder can be referenced from the HTML.
18+
19+
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
20+
work correctly both with client-side routing and a non-root public URL.
21+
Learn how to configure a non-root public URL by running `npm run build`.
22+
-->
23+
<title>React App</title>
24+
</head>
25+
26+
<body>
27+
<noscript>
28+
You need to enable JavaScript to run this app.
29+
</noscript>
30+
<div id="root"></div>
31+
<!--
32+
This HTML file is a template.
33+
If you open it directly in the browser, you will see an empty page.
34+
35+
You can add webfonts, meta tags, or analytics to this file.
36+
The build step will place the bundled scripts into the <body> tag.
37+
38+
To begin the development, run `npm start` or `yarn start`.
39+
To create a production bundle, use `npm run build` or `yarn build`.
40+
-->
41+
</body>
42+
43+
</html>
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import React, { useContext } from "react";
2+
import { AppContext, AppProvider } from "./store/context";
3+
import { ACTION } from "./store/reducer";
4+
5+
interface Props {}
6+
7+
const Children: React.FC = () => {
8+
const { state, dispatch } = useContext(AppContext);
9+
return (
10+
<>
11+
Count: {state.count}
12+
<div>
13+
<button onClick={() => dispatch({ type: ACTION.INCREMENT })}>
14+
INCREMENT
15+
</button>
16+
<button onClick={() => dispatch({ type: ACTION.SET, payload: 10 })}>
17+
SET 10
18+
</button>
19+
</div>
20+
</>
21+
);
22+
};
23+
24+
const App: React.FC<Props> = () => {
25+
return (
26+
<AppProvider>
27+
<Children />
28+
</AppProvider>
29+
);
30+
};
31+
32+
export default App;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { render } from "react-dom";
2+
3+
import App from "./App";
4+
5+
const rootElement = document.getElementById("root");
6+
render(<App />, rootElement);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/// <reference types="react-scripts" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React, { createContext, Dispatch, useReducer } from "react";
2+
import { reducer, initialState, Action } from "./reducer";
3+
4+
export interface ContextProps {
5+
state: {
6+
count: number;
7+
};
8+
dispatch: Dispatch<Action>;
9+
}
10+
11+
const defaultContext: ContextProps = {
12+
state: {
13+
count: 1
14+
},
15+
dispatch: () => void 0
16+
};
17+
18+
export const AppContext = createContext<ContextProps>(defaultContext);
19+
export const AppProvider: React.FC = (props) => {
20+
const { children } = props;
21+
const [state, dispatch] = useReducer(reducer, initialState);
22+
return (
23+
<AppContext.Provider value={{ state, dispatch }}>
24+
{children}
25+
</AppContext.Provider>
26+
);
27+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
export const initialState = { count: 0 };
2+
type State = typeof initialState;
3+
4+
export const ACTION = {
5+
INCREMENT: "INCREMENT" as const,
6+
SET: "SET" as const
7+
};
8+
type IncrementAction = {
9+
type: typeof ACTION.INCREMENT;
10+
};
11+
type SetAction = {
12+
type: typeof ACTION.SET;
13+
payload: number;
14+
};
15+
export type Action = IncrementAction | SetAction;
16+
17+
export const reducer = (state: State, action: Action) => {
18+
switch (action.type) {
19+
case ACTION.INCREMENT:
20+
return { count: state.count + 1 };
21+
case ACTION.SET:
22+
return { count: action.payload };
23+
default:
24+
throw new Error();
25+
}
26+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"include": [
3+
"./src/**/*"
4+
],
5+
"compilerOptions": {
6+
"strict": true,
7+
"esModuleInterop": true,
8+
"lib": [
9+
"dom",
10+
"es2015"
11+
],
12+
"jsx": "react-jsx",
13+
"target": "es5",
14+
"allowJs": true,
15+
"skipLibCheck": true,
16+
"allowSyntheticDefaultImports": true,
17+
"forceConsistentCasingInFileNames": true,
18+
"noFallthroughCasesInSwitch": true,
19+
"module": "esnext",
20+
"moduleResolution": "node",
21+
"resolveJsonModule": true,
22+
"isolatedModules": true,
23+
"noEmit": true
24+
}
25+
}

pnpm-lock.yaml

+19
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)