Skip to content

Commit

Permalink
Examples cleanup (rtk-incubator#20)
Browse files Browse the repository at this point in the history
* Rename examples, small cleanup for brevity, show loading highlights in examples
* Add global and app toggle examples
* Make the svelte example a little more fun (or spooky! 👻 )
* Turn on/off polling copy in Svelte example
  • Loading branch information
msutkowski authored Nov 13, 2020
1 parent bd116d2 commit 547c49b
Show file tree
Hide file tree
Showing 61 changed files with 450 additions and 283 deletions.
2 changes: 1 addition & 1 deletion .codesandbox/ci.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"sandboxes": ["new", "react-ts", "/examples/posts-and-counter", "/examples/svelte-counter"]
"sandboxes": ["new", "react-ts", "/examples/react", "/examples/svelte"]
}
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const api = createApi({
return {
url: `users`,
method: 'POST',
body: JSON.stringify(data),
body: data,
};
},
}),
Expand All @@ -62,7 +62,7 @@ const api = createApi({
return {
url: `users/${id}`,
method: 'PATCH',
body: JSON.stringify(patch),
body: patch,
};
},
}),
Expand Down Expand Up @@ -130,7 +130,7 @@ const api = createApi({
return {
url: `users`,
method: 'POST',
body: JSON.stringify(data),
body: data,
};
},
+ invalidates: [{type: 'User'}]
Expand Down Expand Up @@ -169,7 +169,7 @@ const api = createApi({
return {
url: `users`,
method: 'POST',
body: JSON.stringify(data),
body: data,
};
},
- invalidates: [{type: 'User'}]
Expand All @@ -180,7 +180,7 @@ const api = createApi({
return {
url: `users/${id}`,
method: 'PATCH',
body: JSON.stringify(patch),
body: patch,
};
},
- invalidates: [{type: 'User'}]
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,40 +1,28 @@
.row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 100%;
}

.posts-list {
display: flex;
flex-direction: column;
flex-basis: 100%;
flex: 1;
min-height: 200px;
border-right: 1px solid #eee;
padding: 20px;
text-align: left;
}

.column {
display: flex;
flex-direction: column;
flex-basis: 100%;
flex: 3;
}

.column-3 {
flex: 3;
}

.column-1 {
flex: 1;
}

.column-2 {
flex: 2;
}

.text-left {
text-align: left;
}
.row {
display: flex;
flex-wrap: wrap;
width: 100%;
}

.column {
display: flex;
flex-direction: column;
flex-basis: 100%;
flex: 3;
}

.column-3 {
flex: 3;
}

.column-1 {
flex: 1;
}

.column-2 {
flex: 2;
}

.text-left {
text-align: left;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,28 @@ import { Switch, Route, Link } from 'react-router-dom';
import { PostsManager } from './features/posts/PostsManager';
import { CounterList } from './features/counter/CounterList';
import { TimeList } from './features/time/TimeList';
import { PollingToggles } from './features/polling/PollingToggles';
import './App.css';

function App() {
return (
<div className="App">
<div>
<Link to="/">Times</Link> | <Link to="/posts">Posts</Link> | <Link to="/counters">Counter</Link>
<div className="row">
<div className="column column1">
<span>
<Link to="/">Times</Link> | <Link to="/posts">Posts</Link> | <Link to="/counters">Counter</Link>
</span>
</div>
<div className="column column1">
<PollingToggles />
</div>
</div>
<div></div>
<div>
<Switch>
<Route exact path="/" component={TimeList} />
<Route exact path="/counters" component={CounterList} />
<Route exact path="/posts" component={PostsManager} />
<Route path="/posts" component={PostsManager} />
</Switch>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,27 @@ export const counterApi = createApi({
endpoints: (build) => ({
getCount: build.query<CountResponse, void>({
query: () => 'count',
provides: [{ type: 'Counter' }],
provides: ['Counter'],
}),
incrementCount: build.mutation<CountResponse, number>({
query(amount) {
return {
url: `increment`,
method: 'PUT',
body: JSON.stringify({ amount }),
body: { amount },
};
},
invalidates: [{ type: 'Counter' }],
invalidates: ['Counter'],
}),
decrementCount: build.mutation<CountResponse, number>({
query(amount) {
return {
url: `decrement`,
method: 'PUT',
body: JSON.stringify({ amount }),
body: { amount },
};
},
invalidates: [{ type: 'Counter' }],
invalidates: ['Counter'],
}),
}),
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,37 @@ type PostsResponse = Post[];

export const postApi = createApi({
reducerPath: 'postsApi',
baseQuery: fetchBaseQuery(),
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
entityTypes: ['Posts'],
endpoints: (build) => ({
getPosts: build.query<PostsResponse, void>({
query: () => 'posts',
provides: (result) => result.map(({ id }) => ({ type: 'Posts', id })),
}),
addPost: build.mutation<Post, Partial<Post>>({
query(data) {
query(body) {
return {
url: `posts`,
method: 'POST',
body: JSON.stringify(data),
body,
};
},
invalidates: [{ type: 'Posts' }],
invalidates: ['Posts'],
}),
getPost: build.query<Post, number>({
query: (id) => `posts/${id}`,
provides: (result, id) => [{ type: 'Posts', id }],
provides: (_, id) => [{ type: 'Posts', id }],
}),
updatePost: build.mutation<Post, Partial<Post>>({
query(data) {
const { id, ...post } = data;
const { id, ...body } = data;
return {
url: `posts/${id}`,
method: 'PUT',
body: JSON.stringify(post),
body,
};
},
invalidates: (result, { id }) => [{ type: 'Posts', id }],
invalidates: (_, { id }) => [{ type: 'Posts', id }],
}),
deletePost: build.mutation<{ success: boolean; id: number }, number>({
query(id) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const timeApi = createApi({
endpoints: (build) => ({
getTime: build.query<TimeResponse, string>({
query: (id) => `time/${id}`,
provides: (result, id) => [{ type: 'Time', id }],
provides: (_, id) => [{ type: 'Time', id }],
}),
}),
});
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { configureStore, ThunkAction, Action, ConfigureStoreOptions } from '@reduxjs/toolkit';
import { useDispatch } from 'react-redux';
import { configureStore, ConfigureStoreOptions } from '@reduxjs/toolkit';
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
import { counterApi } from './services/counter';
import { postApi } from './services/posts';
import { timeApi } from './services/times';
import polling from '../features/polling/pollingSlice';

export const createStore = (options?: ConfigureStoreOptions['preloadedState'] | undefined) =>
configureStore({
reducer: {
[counterApi.reducerPath]: counterApi.reducer,
[postApi.reducerPath]: postApi.reducer,
[timeApi.reducerPath]: timeApi.reducer,
polling,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(counterApi.middleware, postApi.middleware, timeApi.middleware),
Expand All @@ -21,4 +23,4 @@ export const store = createStore();
export type AppDispatch = typeof store.dispatch;
export const useAppDispatch = () => useDispatch<AppDispatch>();
export type RootState = ReturnType<typeof store.getState>;
export type AppThunk<ReturnType = void> = ThunkAction<ReturnType, RootState, unknown, Action<string>>;
export const useTypedSelector: TypedUseSelectorHook<RootState> = useSelector;
47 changes: 47 additions & 0 deletions examples/react/src/features/polling/PollingToggles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import { useAppDispatch, useTypedSelector } from '../../app/store';
import {
selectGlobalPollingEnabled,
selectPollingConfigByApp,
toggleGlobalPolling,
updatePolling,
} from './pollingSlice';

const PollingToggleButton = ({
enabled,
onClick,
children,
}: {
onClick: () => void;
enabled: boolean;
children?: React.ReactNode;
}) => {
return (
<button onClick={onClick} style={enabled ? { background: 'lightgreen' } : {}}>
{children}
</button>
);
};

export const PollingToggles = () => {
const dispatch = useAppDispatch();
const globalPolling = useTypedSelector(selectGlobalPollingEnabled);
const timesPolling = useTypedSelector((state) => selectPollingConfigByApp(state, 'times'));

return (
<div>
<small>Global Polling Configs</small>
<div>
<PollingToggleButton enabled={globalPolling} onClick={() => dispatch(toggleGlobalPolling())}>
Global
</PollingToggleButton>
<PollingToggleButton
enabled={timesPolling.enabled}
onClick={() => dispatch(updatePolling({ app: 'times', enabled: !timesPolling.enabled }))}
>
Times
</PollingToggleButton>
</div>
</div>
);
};
67 changes: 67 additions & 0 deletions examples/react/src/features/polling/pollingSlice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { RootState } from '../../app/store';

type PollingConfig = {
enabled: boolean;
interval: number;
};

type SliceState = {
enabled: boolean;
apps: {
[key: string]: PollingConfig;
};
};

const initialState: SliceState = {
enabled: true,
apps: {
counters: {
enabled: true,
interval: 0,
},
times: {
enabled: true,
interval: 0,
},
posts: {
enabled: true,
interval: 0,
},
},
};

type PollingAppKey = keyof typeof initialState['apps'];

const slice = createSlice({
name: 'polling',
initialState,
reducers: {
toggleGlobalPolling(state) {
state.enabled = !state.enabled;
},
updatePolling(
state,
{
payload,
}: PayloadAction<{
app: PollingAppKey;
enabled?: boolean;
interval?: number;
}>
) {
const { app, ...rest } = payload;
state.apps[app] = {
...state.apps[app],
...rest,
};
},
},
});

export const { toggleGlobalPolling, updatePolling } = slice.actions;

export default slice.reducer;

export const selectGlobalPollingEnabled = (state: RootState) => state.polling.enabled;
export const selectPollingConfigByApp = (state: RootState, app: PollingAppKey) => state.polling.apps[app];
Loading

0 comments on commit 547c49b

Please sign in to comment.