Skip to content

Commit

Permalink
Add Expo and React Native examples to CI (reduxjs#4681)
Browse files Browse the repository at this point in the history
Co-authored-by: Tim Dorr <[email protected]>
Co-authored-by: Tim Dorr <[email protected]>
  • Loading branch information
3 people committed Mar 21, 2024
1 parent ae77ef0 commit 4179157
Show file tree
Hide file tree
Showing 127 changed files with 1,106 additions and 1,173 deletions.
4 changes: 2 additions & 2 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ module.exports = {
],
'@typescript-eslint/consistent-type-imports': [
'error',
{ prefer: 'type-imports', disallowTypeAnnotations: false }
]
{ prefer: 'type-imports', disallowTypeAnnotations: false },
],
}
}
6 changes: 3 additions & 3 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: 🤔 Questions and Help
url: https://redux.js.org/introduction/getting-started#help-and-discussion
about: This is a bug tracker, not a support system. For usage questions, please use our support resources.
- name: 🤔 Questions and Help
url: https://redux.js.org/introduction/getting-started#help-and-discussion
about: This is a bug tracker, not a support system. For usage questions, please use our support resources.
20 changes: 17 additions & 3 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,17 @@ jobs:
fail-fast: false
matrix:
node: ['20.x']
example: ['cra4', 'cra5', 'next', 'vite', 'node-standard', 'node-esm']
example:
[
'cra4',
'cra5',
'next',
'vite',
'node-standard',
'node-esm',
'react-native',
'expo'
]
steps:
- name: Checkout repo
uses: actions/checkout@v4
Expand All @@ -180,13 +190,17 @@ jobs:
- name: Clone RTK repo
run: git clone https://github.com/reduxjs/redux-toolkit.git ./redux-toolkit

- name: Cache example deps
uses: actions/cache@v4
with:
path: ./redux-toolkit/examples/publish-ci/${{ matrix.example }}/node_modules
key: test-published-artifact-${{ matrix.example }}-node_modules

- name: Check folder contents
run: ls -l .

- name: Install deps
working-directory: ./redux-toolkit/examples/publish-ci/${{ matrix.example }}
env:
YARN_ENABLE_IMMUTABLE_INSTALLS: false
run: yarn install

- uses: actions/download-artifact@v4
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# <a href='https://redux.js.org'><img src='https://avatars.githubusercontent.com/u/13142323?s=200&v=4' height='60' alt='Redux Logo' aria-label='redux.js.org' style="display: flex;align-items: center;"/>Redux</a>
# <a href='https://redux.js.org'><img src='https://avatars.githubusercontent.com/u/13142323?s=200&v=4' height='60' alt='Redux Logo' aria-label='redux.js.org' style="display: flex;align-items: center;"/>Redux</a>

Redux is a predictable state container for JavaScript apps.

Expand Down
2 changes: 1 addition & 1 deletion docs/api/combineReducers.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export default combineReducers({
#### `App.js`

```js
import { configureStore } from '@reduxjs/toolkit'
import { configureStore } from '@reduxjs/toolkit'
import reducer from './reducers/index'

const store = configureStore({
Expand Down
4 changes: 2 additions & 2 deletions docs/usage/WritingTests.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ interface ExtendedRenderOptions extends Omit<RenderOptions, 'queries'> {

export function renderWithProviders(
ui: React.ReactElement,
extendedRenderOptions: ExtendedRenderOptions = {}
extendedRenderOptions: ExtendedRenderOptions = {},
) {
const {
preloadedState = {},
Expand All @@ -367,7 +367,7 @@ export function renderWithProviders(
// Return an object with the store and all of RTL's query functions
return {
store,
...render(ui, { wrapper: Wrapper, ...renderOptions })
...render(ui, { wrapper: Wrapper, ...renderOptions }),
}
}
```
Expand Down
23 changes: 10 additions & 13 deletions docs/usage/migrating-to-modern-redux.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ This example shows several possible common tasks when setting up a Redux store:
None of these are _required_, but they do show up frequently in real-world codebases.

```js title="Custom Store Setup: src/app/store.js"
import { configureStore, combineReducers } from '@reduxjs/toolkit'
import { configureStore, combineReducers} from '@reduxjs/toolkit'
import {
persistStore,
persistReducer,
Expand All @@ -139,7 +139,7 @@ import {
PAUSE,
PERSIST,
PURGE,
REGISTER
REGISTER,
} from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import { PersistGate } from 'redux-persist/integration/react'
Expand All @@ -163,7 +163,7 @@ const rootReducer = combineReducers({
const persistConfig = {
key: 'root',
version: 1,
storage
storage,
}

const persistedReducer = persistReducer(persistConfig, rootReducer)
Expand All @@ -175,12 +175,12 @@ const store = configureStore({
const middleware = getDefaultMiddleware({
// Pass in a custom `extra` argument to the thunk middleware
thunk: {
extraArgument: { serviceLayer }
extraArgument: {serviceLayer}
},
// Customize the built-in serializability dev check
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER]
}
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
},
}).concat(customMiddleware, api.middleware)

// Conditionally add another middleware in dev
Expand All @@ -191,12 +191,9 @@ const store = configureStore({
return middleware
},
// Turn off devtools in prod, or pass options in dev
devTools:
process.env.NODE_ENV === 'production'
? false
: {
stateSanitizer: stateSanitizerForDevtools
}
devTools: process.env.NODE_ENV === 'production' ? false : {
stateSanitizer: stateSanitizerForDevtools
}
})
```

Expand Down Expand Up @@ -820,7 +817,7 @@ export const store = createStore(rootReducer)
export type RootAction = TodoActions | CounterActions
// ❌ Common pattern: manually defining the root state type with each field
export interface RootState {
todos: TodosState
todos: TodosState;
counter: CounterState
}
Expand Down
2 changes: 1 addition & 1 deletion errors.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@
"15": "Dispatching while constructing your middleware is not allowed. Other middleware would not be applied to this dispatch.",
"16": "bindActionCreators expected an object or a function, but instead received: ''. Did you write \"import ActionCreators from\" instead of \"import * as ActionCreators from\"?",
"17": "Action \"type\" property must be a string. Instead, the actual type was: ''. Value was: '' (stringified)"
}
}
6 changes: 3 additions & 3 deletions examples/async/public/index.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Redux Async Example</title>
</head>
<body>
Expand Down
13 changes: 8 additions & 5 deletions examples/async/src/components/Picker.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,21 @@ import PropTypes from 'prop-types'
const Picker = ({ value, onChange, options }) => (
<span>
<h1>{value}</h1>
<select onChange={e => onChange(e.target.value)} value={value}>
{options.map(option => (
<select onChange={e => onChange(e.target.value)}
value={value}>
{options.map(option =>
<option value={option} key={option}>
{option}
</option>
))}
</option>)
}
</select>
</span>
)

Picker.propTypes = {
options: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired,
options: PropTypes.arrayOf(
PropTypes.string.isRequired
).isRequired,
value: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired
}
Expand Down
6 changes: 3 additions & 3 deletions examples/async/src/components/Posts.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React from 'react'
import PropTypes from 'prop-types'

const Posts = ({ posts }) => (
const Posts = ({posts}) => (
<ul>
{posts.map((post, i) => (
{posts.map((post, i) =>
<li key={i}>{post.title}</li>
))}
)}
</ul>
)

Expand Down
46 changes: 19 additions & 27 deletions examples/async/src/containers/App.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import {
selectSubreddit,
fetchPostsIfNeeded,
invalidateSubreddit
} from '../actions'
import { selectSubreddit, fetchPostsIfNeeded, invalidateSubreddit } from '../actions'
import Picker from '../components/Picker'
import Posts from '../components/Posts'

Expand Down Expand Up @@ -47,32 +43,28 @@ class App extends Component {
const isEmpty = posts.length === 0
return (
<div>
<Picker
value={selectedSubreddit}
onChange={this.handleChange}
options={['reactjs', 'frontend']}
/>
<Picker value={selectedSubreddit}
onChange={this.handleChange}
options={[ 'reactjs', 'frontend' ]} />
<p>
{lastUpdated && (
{lastUpdated &&
<span>
Last updated at {new Date(lastUpdated).toLocaleTimeString()}.{' '}
Last updated at {new Date(lastUpdated).toLocaleTimeString()}.
{' '}
</span>
)}
{!isFetching && (
<button onClick={this.handleRefreshClick}>Refresh</button>
)}
}
{!isFetching &&
<button onClick={this.handleRefreshClick}>
Refresh
</button>
}
</p>
{isEmpty ? (
isFetching ? (
<h2>Loading...</h2>
) : (
<h2>Empty.</h2>
)
) : (
<div style={{ opacity: isFetching ? 0.5 : 1 }}>
<Posts posts={posts} />
</div>
)}
{isEmpty
? (isFetching ? <h2>Loading...</h2> : <h2>Empty.</h2>)
: <div style={{ opacity: isFetching ? 0.5 : 1 }}>
<Posts posts={posts} />
</div>
}
</div>
)
}
Expand Down
7 changes: 5 additions & 2 deletions examples/async/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ import { createLogger } from 'redux-logger'
import reducer from './reducers'
import App from './containers/App'

const middleware = [thunk]
const middleware = [ thunk ]
if (process.env.NODE_ENV !== 'production') {
middleware.push(createLogger())
}

const store = createStore(reducer, applyMiddleware(...middleware))
const store = createStore(
reducer,
applyMiddleware(...middleware)
)

render(
<Provider store={store}>
Expand Down
21 changes: 8 additions & 13 deletions examples/async/src/reducers/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { combineReducers } from 'redux'
import {
SELECT_SUBREDDIT,
INVALIDATE_SUBREDDIT,
REQUEST_POSTS,
RECEIVE_POSTS
SELECT_SUBREDDIT, INVALIDATE_SUBREDDIT,
REQUEST_POSTS, RECEIVE_POSTS
} from '../actions'

const selectedSubreddit = (state = 'reactjs', action) => {
Expand All @@ -15,14 +13,11 @@ const selectedSubreddit = (state = 'reactjs', action) => {
}
}

const posts = (
state = {
isFetching: false,
didInvalidate: false,
items: []
},
action
) => {
const posts = (state = {
isFetching: false,
didInvalidate: false,
items: []
}, action) => {
switch (action.type) {
case INVALIDATE_SUBREDDIT:
return {
Expand All @@ -48,7 +43,7 @@ const posts = (
}
}

const postsBySubreddit = (state = {}, action) => {
const postsBySubreddit = (state = { }, action) => {
switch (action.type) {
case INVALIDATE_SUBREDDIT:
case RECEIVE_POSTS:
Expand Down
16 changes: 8 additions & 8 deletions examples/counter-ts/src/App.test.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import React from 'react'
import { render } from '@testing-library/react'
import { Provider } from 'react-redux'
import { store } from './app/store'
import App from './App'
import React from 'react';
import { render } from '@testing-library/react';
import { Provider } from 'react-redux';
import { store } from './app/store';
import App from './App';

test('renders learn react link', () => {
const { getByText } = render(
<Provider store={store}>
<App />
</Provider>
)
);

expect(getByText(/learn/i)).toBeInTheDocument()
})
expect(getByText(/learn/i)).toBeInTheDocument();
});
2 changes: 1 addition & 1 deletion examples/counter-ts/src/app/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ import type { AppDispatch, RootState } from './store'

// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
export const useAppSelector = useSelector.withTypes<RootState>()
export const useAppSelector = useSelector.withTypes<RootState>()
16 changes: 8 additions & 8 deletions examples/counter-ts/src/app/store.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { configureStore, ThunkAction, Action } from '@reduxjs/toolkit'
import counterReducer from '../features/counter/counterSlice'
import { configureStore, ThunkAction, Action } from '@reduxjs/toolkit';
import counterReducer from '../features/counter/counterSlice';

export const store = configureStore({
reducer: {
counter: counterReducer
}
})
counter: counterReducer,
},
});

export type AppDispatch = typeof store.dispatch
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch;
export type RootState = ReturnType<typeof store.getState>;
export type AppThunk<ReturnType = void> = ThunkAction<
ReturnType,
RootState,
unknown,
Action<string>
>
>;
Loading

0 comments on commit 4179157

Please sign in to comment.