diff --git a/README.md b/README.md index 7514161ef..7706ecdd8 100644 --- a/README.md +++ b/README.md @@ -5,21 +5,25 @@ Performant and flexible. ![GitHub Workflow Status](https://img.shields.io/github/workflow/status/reduxjs/react-redux/Tests?style=flat-square) [![npm version](https://img.shields.io/npm/v/react-redux.svg?style=flat-square)](https://www.npmjs.com/package/react-redux) [![npm downloads](https://img.shields.io/npm/dm/react-redux.svg?style=flat-square)](https://www.npmjs.com/package/react-redux) -[![redux channel on discord](https://img.shields.io/badge/discord-redux@reactiflux-61DAFB.svg?style=flat-square)](http://www.reactiflux.com) +[![#redux channel on Discord](https://img.shields.io/badge/discord-redux@reactiflux-61DAFB.svg?style=flat-square)](http://www.reactiflux.com) ## Installation ### Using Create React App -The recommended way to start new apps with React Redux is by using the [official Redux+JS template](https://github.com/reduxjs/cra-template-redux) for [Create React App](https://github.com/facebook/create-react-app), which takes advantage of [Redux Toolkit](https://redux-toolkit.js.org/). +The recommended way to start new apps with React Redux is by using the [official Redux+JS/TS templates](https://github.com/reduxjs/cra-template-redux) for [Create React App](https://github.com/facebook/create-react-app), which takes advantage of [Redux Toolkit](https://redux-toolkit.js.org/). ```sh +# JS npx create-react-app my-app --template redux + +# TS +npx create-react-app my-app --template redux-typescript ``` ### An Existing React App -React Redux 7.1 requires **React 16.8.3 or later.** +React Redux 8.0 requires **React 16.8.3 or later** (or React Native 0.59 or later). To use React Redux with your React app, install it as a dependency: @@ -40,24 +44,16 @@ modules](https://webpack.js.org/api/module-methods/#commonjs). If you don’t yet use [npm](http://npmjs.com/) or a modern module bundler, and would rather prefer a single-file [UMD](https://github.com/umdjs/umd) build that makes `ReactRedux` available as a global object, you can grab a pre-built version from [cdnjs](https://cdnjs.com/libraries/react-redux). We _don’t_ recommend this approach for any serious application, as most of the libraries complementary to Redux are only available on [npm](http://npmjs.com/). -## React Native - -As of React Native 0.18, React Redux 5.x should work with React Native. If you have any issues with React Redux 5.x on React Native, run `npm ls react` and make sure you don’t have a duplicate React installation in your `node_modules`. We recommend that you use `npm@3.x` which is better at avoiding these kinds of issues. - ## Documentation -The React Redux docs are now published at **https://react-redux.js.org** . - -We're currently expanding and rewriting our docs content - check back soon for more updates! +The React Redux docs are published at **https://react-redux.js.org** . ## How Does It Work? -We do a deep dive on how React Redux works in [this readthesource episode](https://www.youtube.com/watch?v=VJ38wSFbM3A). - -Also, the post [The History and Implementation of React-Redux](https://blog.isquaredsoftware.com/2018/11/react-redux-history-implementation/) +The post [The History and Implementation of React-Redux](https://blog.isquaredsoftware.com/2018/11/react-redux-history-implementation/) explains what it does, how it works, and how the API and implementation have evolved over time. -Enjoy! +There's also a [Deep Dive into React-Redux](https://blog.isquaredsoftware.com/2019/06/presentation-react-redux-deep-dive/) talk that covers some of the same material at a higher level. ## License diff --git a/docs/api/Provider.md b/docs/api/Provider.md index 3eb7d2bcb..3c9ef6115 100644 --- a/docs/api/Provider.md +++ b/docs/api/Provider.md @@ -20,20 +20,51 @@ The [Hooks](./hooks.md) and [`connect`](./connect.md) APIs can then access the p ### Props -`store` ([Redux Store](https://redux.js.org/api/store)) -The single Redux `store` in your application. +```ts +interface ProviderProps { + /** + * The single Redux store in your application. + */ + store: Store + + /** + * An optional server state snapshot. Will be used during initial hydration render + * if available, to ensure that the UI output is consistent with the HTML generated on the server. + * New in 8.0 + */ + serverState?: S + + /** + * Optional context to be used internally in react-redux. Use React.createContext() + * to create a context to be used. + * If this is used, you'll need to customize `connect` by supplying the same + * context provided to the Provider. + * Initial value doesn't matter, as it is overwritten with the internal state of Provider. + */ + context?: Context> + + /** The top-level React elements in your component tree, such as `` **/ + children: ReactNode +} +``` -`children` (ReactElement) -The root of your component hierarchy. +Typically, you only need to pass ``. -`context` -You may provide a context instance. If you do so, you will need to provide the same context instance to all of your connected components as well. Failure to provide the correct context results in runtime error: +You may provide a context instance. If you do so, you will need to provide the same context instance to all of your connected components as well. Failure to provide the correct context results in this runtime error: > Invariant Violation > > Could not find "store" in the context of "Connect(MyComponent)". Either wrap the root component in a ``, or pass a custom React context provider to `` and the corresponding React context consumer to Connect(Todo) in connect options. -### Example Usage +## React 18 SSR Usage + +As of React-Redux v8, `` now accepts a `serverState` prop for use in SSR hydration scenarios. This is necessary if you are calling `hydrateRoot` in order to avoid hydration mismatches. + +You should pass the entire serialized state from the server as the `serverState` prop, and React will use this state for the initial hydration render. After that, it will apply any updates from changes that occurred on the client during the setup process. + +## Examples + +### Basic Usage In the example below, the `` component is our root-level component. This means it’s at the very top of our component hierarchy. @@ -47,10 +78,35 @@ import createStore from './createReduxStore' const store = createStore() -ReactDOM.render( +// As of React 18 +const root = ReactDOM.createRoot(document.getElementById('root')) +root.render( - , - document.getElementById('root') + +) +``` + +### React 18 SSR Hydration + +In this example, the client has received HTML rendered by the server, as well as a serialized Redux state attached to `window`. The serialized state is used to both pre-fill the store's contents, _and_ passed as the `serverState` prop to `` + +```tsx title="src/index.ts" +import { hydrateRoot } from 'react-dom/client' +import { configureStore } from '@reduxjs/toolkit' +import { Provider } from 'react-redux' + +const preloadedState = window.__PRELOADED_STATE__ + +const clientStore = configureStore({ + reducer: rootReducer, + preloadedState, +}) + +hydrateRoot( + document.getElementById('root'), + + + ) ``` diff --git a/docs/api/batch.md b/docs/api/batch.md index 8f963c46a..9b0beb0b8 100644 --- a/docs/api/batch.md +++ b/docs/api/batch.md @@ -11,16 +11,22 @@ description: 'API > batch: batching React rendering updates' # `batch()` ```js -batch((fn: Function)) +batch((fn: () => void)) ``` _added in v7.0.0_ +:::info + +**If you're using React 18, you do not need to use the `batch` API**. React 18 automatically batches _all_ state updates, no matter where they're queued. + +::: + React's `unstable_batchedUpdates()` API allows any React updates in an event loop tick to be batched together into a single render pass. React already uses this internally for its own event handler callbacks. This API is actually part of the renderer packages like ReactDOM and React Native, not the React core itself. Since React-Redux needs to work in both ReactDOM and React Native environments, we've taken care of importing this API from the correct renderer at build time for our own use. We also now re-export this function publicly ourselves, renamed to `batch()`. You can use it to ensure that multiple actions dispatched outside of React only result in a single render update, like this: -```js +```ts import { batch } from 'react-redux' function myThunk() { @@ -37,3 +43,4 @@ function myThunk() { ## References - [`unstable_batchedUpdates()` API from React](https://github.com/facebook/react/commit/b41883fc708cd24d77dcaa767cde814b50b457fe) +- [React 18 Working Group: Automatic Batching for Fewer Renders in React 18](https://github.com/reactwg/react-18/discussions/21) diff --git a/docs/api/connect-advanced.md b/docs/api/connect-advanced.md deleted file mode 100644 index c205b1fed..000000000 --- a/docs/api/connect-advanced.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -id: connect-advanced -title: connectAdvanced -sidebar_label: connectAdvanced() -hide_title: true -description: 'API > connectAdvanced: customizing connect for advanced behavior' ---- - -  - -# `connectAdvanced()` - -```js -connectAdvanced(selectorFactory, connectOptions?) -``` - -Connects a React component to a Redux store. It is the base for `connect()` but is less opinionated about how to combine `state`, `props`, and `dispatch` into your final props. It makes no assumptions about defaults or memoization of results, leaving those responsibilities to the caller. - -It does not modify the component class passed to it; instead, it _returns_ a new, connected component class for you to use. - -Most applications will not need to use this, as the default behavior in `connect` is intended to work for most use cases. - -:::info - -`connectAdvanced` was added in version 5.0, and `connect` was reimplemented as a specific set of parameters to `connectAdvanced`. However, [**`connectAdvanced` is now deprecated**](https://github.com/reduxjs/react-redux/issues/1236) and will eventually be removed in a future major version of React Redux. - -::: - -## Arguments - -- `selectorFactory(dispatch, factoryOptions): selector(state, ownProps): props` \(_Function_): Initializes a selector function (during each instance's constructor). That selector function is called any time the connector component needs to compute new props, as a result of a store state change or receiving new props. The result of `selector` is expected to be a plain object, which is passed as the props to the wrapped component. If a consecutive call to `selector` returns the same object (`===`) as its previous call, the component will not be re-rendered. It's the responsibility of `selector` to return that previous object when appropriate. - -- [`connectOptions`] _(Object)_ If specified, further customizes the behavior of the connector. - - - [`getDisplayName`] _(Function)_: computes the connector component's displayName property relative to that of the wrapped component. Usually overridden by wrapper functions. Default value: `name => 'ConnectAdvanced('+name+')'` - - - [`methodName`] _(String)_: shown in error messages. Usually overridden by wrapper functions. Default value: `'connectAdvanced'` - - - [`renderCountProp`] _(String)_: if defined, a property named this value will be added to the props passed to the wrapped component. Its value will be the number of times the component has been rendered, which can be useful for tracking down unnecessary re-renders. Default value: `undefined` - - - [`shouldHandleStateChanges`] _(Boolean)_: controls whether the connector component subscribes to redux store state changes. If set to false, it will only re-render when parent component re-renders. Default value: `true` - - - [`forwardRef`] _(Boolean)_: If true, adding a ref to the connected wrapper component will actually return the instance of the wrapped component. - - - Additionally, any extra options passed via `connectOptions` will be passed through to your `selectorFactory` in the `factoryOptions` argument. - - - -## Returns - -A higher-order React component class that builds props from the store state and passes them to the wrapped component. A higher-order component is a function which accepts a component argument and returns a new component. - -### Static Properties - -- `WrappedComponent` _(Component)_: The original component class passed to `connectAdvanced(...)(Component)`. - -### Static Methods - -All the original static methods of the component are hoisted. - -## Remarks - -- Since `connectAdvanced` returns a higher-order component, it needs to be invoked two times. The first time with its arguments as described above, and a second time, with the component: `connectAdvanced(selectorFactory)(MyComponent)`. - -- `connectAdvanced` does not modify the passed React component. It returns a new, connected component, that you should use instead. - - - -### Examples - -### Inject `todos` of a specific user depending on props, and inject `props.userId` into the action - -```js -import * as actionCreators from './actionCreators' -import { bindActionCreators } from 'redux' - -function selectorFactory(dispatch) { - let ownProps = {} - let result = {} - - const actions = bindActionCreators(actionCreators, dispatch) - const addTodo = (text) => actions.addTodo(ownProps.userId, text) - - return (nextState, nextOwnProps) => { - const todos = nextState.todos[nextOwnProps.userId] - const nextResult = { ...nextOwnProps, todos, addTodo } - ownProps = nextOwnProps - if (!shallowEqual(result, nextResult)) result = nextResult - return result - } -} -export default connectAdvanced(selectorFactory)(TodoApp) -``` diff --git a/docs/api/connect.md b/docs/api/connect.md index d143ea9fd..6d177d25e 100644 --- a/docs/api/connect.md +++ b/docs/api/connect.md @@ -10,6 +10,12 @@ description: 'API > connect: a Higher-Order Component to interact with Redux' # `connect()` +:::tip + +`connect` still works and is supported in React-Redux 8.x. However, [**we recommend using the hooks API as the default**](./hooks.md). + +::: + ## Overview The `connect()` function connects a React component to a Redux store. @@ -202,7 +208,6 @@ The return value of `mergeProps` is referred to as `mergedProps` and the fields ```js { context?: Object, - pure?: boolean, areStatesEqual?: Function, areOwnPropsEqual?: Function, areStatePropsEqual?: Function, @@ -226,23 +231,11 @@ connect(mapStateToProps, mapDispatchToProps, null, { context: MyContext })( ) ``` -#### `pure: boolean` - -- default value: `true` - -Assumes that the wrapped component is a “pure” component and does not rely on any input or state other than its props and the selected Redux store’s state. - -When `options.pure` is true, `connect` performs several equality checks that are used to avoid unnecessary calls to `mapStateToProps`, `mapDispatchToProps`, `mergeProps`, and ultimately to `render`. These include `areStatesEqual`, `areOwnPropsEqual`, `areStatePropsEqual`, and `areMergedPropsEqual`. While the defaults are probably appropriate 99% of the time, you may wish to override them with custom implementations for performance or other reasons. - -We provide a few examples in the following sections. - #### `areStatesEqual: (next: Object, prev: Object) => boolean` - default value: `strictEqual: (next, prev) => prev === next` -When pure, compares incoming store state to its previous value. - -_Example 1_ +Compares incoming store state to its previous value. ```js const areStatesEqual = (next, prev) => @@ -251,14 +244,6 @@ const areStatesEqual = (next, prev) => You may wish to override `areStatesEqual` if your `mapStateToProps` function is computationally expensive and is also only concerned with a small slice of your state. The example above will effectively ignore state changes for everything but that slice of state. -_Example 2_ - -If you have impure reducers that mutate your store state, you may wish to override `areStatesEqual` to always return false: - -```js -const areStatesEqual = () => false -``` - This would likely impact the other equality checks as well, depending on your `mapStateToProps` function. #### `areOwnPropsEqual: (next: Object, prev: Object) => boolean` @@ -266,7 +251,7 @@ This would likely impact the other equality checks as well, depending on your `m - default value: `shallowEqual: (objA, objB) => boolean` ( returns `true` when each field of the objects is equal ) -When pure, compares incoming props to its previous value. +Compares incoming props to its previous value. You may wish to override `areOwnPropsEqual` as a way to whitelist incoming props. You'd also have to implement `mapStateToProps`, `mapDispatchToProps` and `mergeProps` to also whitelist props. (It may be simpler to achieve this other ways, for example by using [recompose's mapProps](https://github.com/acdlite/recompose/blob/master/docs/API.md#mapprops).) @@ -275,13 +260,13 @@ You may wish to override `areOwnPropsEqual` as a way to whitelist incoming props - type: `function` - default value: `shallowEqual` -When pure, compares the result of `mapStateToProps` to its previous value. +Compares the result of `mapStateToProps` to its previous value. #### `areMergedPropsEqual: (next: Object, prev: Object) => boolean` - default value: `shallowEqual` -When pure, compares the result of `mergeProps` to its previous value. +Compares the result of `mergeProps` to its previous value. You may wish to override `areStatePropsEqual` to use `strictEqual` if your `mapStateToProps` uses a memoized selector that will only return a new object if a relevant prop has changed. This would be a very slight performance improvement, since would avoid extra equality checks on individual props each time `mapStateToProps` is called. diff --git a/docs/api/hooks.md b/docs/api/hooks.md index e4f3ac7cb..db8d20840 100644 --- a/docs/api/hooks.md +++ b/docs/api/hooks.md @@ -31,11 +31,12 @@ As with `connect()`, you should start by wrapping your entire application in a ` ```jsx const store = createStore(rootReducer) -ReactDOM.render( +// As of React 18 +const root = ReactDOM.createRoot(document.getElementById('root')) +root.render( - , - document.getElementById('root') + ) ``` @@ -79,7 +80,7 @@ When the function component renders, the provided selector function will be call from the `useSelector()` hook. (A cached result may be returned by the hook without re-running the selector if it's the same function reference as on a previous render of the component.) However, when an action is dispatched to the Redux store, `useSelector()` only forces a re-render if the selector result -appears to be different than the last result. As of v7.1.0-alpha.5, the default comparison is a strict `===` reference +appears to be different than the last result. The default comparison is a strict `===` reference comparison. This is different than `connect()`, which uses shallow equality checks on the results of `mapState` calls to determine if re-rendering is needed. This has several implications on how you should use `useSelector()`. @@ -289,17 +290,18 @@ Normally, that store instance never changes in an application. However, the React hooks lint rules do not know that `dispatch` should be stable, and will warn that the `dispatch` variable should be added to dependency arrays for `useEffect` and `useCallback`. The simplest solution is to do just that: -````js +```js export const Todos = () => { - const dispatch = useDispatch(); + const dispatch = useDispatch() useEffect(() => { dispatch(fetchTodos()) - // highlight-start - // Safe to add dispatch to the dependencies array + // highlight-start + // Safe to add dispatch to the dependencies array }, [dispatch]) // highlight-end } +``` ::: @@ -315,7 +317,7 @@ This hook should probably not be used frequently. Prefer `useSelector()` as your #### Examples -```jsx +```js import React from 'react' import { useStore } from 'react-redux' @@ -340,7 +342,7 @@ import { Provider, createStoreHook, createDispatchHook, - createSelectorHook + createSelectorHook, } from 'react-redux' const MyContext = React.createContext(null) @@ -369,6 +371,8 @@ export function MyProvider({ children }) { The React-Redux hooks API has been production-ready since we released it in v7.1.0, and **we recommend using the hooks API as the default approach in your components**. However, there are a couple of edge cases that can occur, and **we're documenting those so that you can be aware of them**. +In practice, these are a rare concern - we've received far more comments about these being in the docs than actual reports of these being a real problem in an app. + ::: One of the most difficult aspects of React Redux's implementation is ensuring that if your `mapStateToProps` function is defined as `(state, ownProps)`, it will be called with the "latest" props every time. Up through version 4, there were recurring bugs reported involving edge case situations, such as errors thrown from a `mapState` function for a list item whose data had just been deleted. @@ -405,7 +409,7 @@ If you prefer to deal with this issue yourself, here are some possible options f For a longer description of these scenarios, see: - ["Stale props and zombie children in Redux" by Kai Hao](https://kaihao.dev/posts/Stale-props-and-zombie-children-in-Redux) -- [this chat log that describes the problems in more detail](https://gist.github.com/markerikson/faac6ae4aca7b82a058e13216a7888ec) +- [A chat log that describes the problems in more detail](https://gist.github.com/markerikson/faac6ae4aca7b82a058e13216a7888ec) - [issue #1179](https://github.com/reduxjs/react-redux/issues/1179) ::: @@ -418,7 +422,7 @@ If further performance optimizations are necessary, you may consider wrapping yo ```jsx const CounterComponent = ({ name }) => { - const counter = useSelector(state => state.counter) + const counter = useSelector((state) => state.counter) return (
{name}: {counter} @@ -459,7 +463,7 @@ export function useActions(actions, deps) { return useMemo( () => { if (Array.isArray(actions)) { - return actions.map(a => bindActionCreators(a, dispatch)) + return actions.map((a) => bindActionCreators(a, dispatch)) } return bindActionCreators(actions, dispatch) }, diff --git a/docs/introduction/getting-started.md b/docs/introduction/getting-started.md index 7261a7c09..f0bbb2d47 100644 --- a/docs/introduction/getting-started.md +++ b/docs/introduction/getting-started.md @@ -17,7 +17,7 @@ import 'react-lite-youtube-embed/dist/LiteYouTubeEmbed.css' ## Installation -React Redux 7.1+ requires **React 16.8.3 or later**, in order to make use of React Hooks. +React Redux 8.x requires **React 16.8.3 or later** / **React Native 0.59 or later**, in order to make use of React Hooks. ### Using Create React App @@ -45,11 +45,7 @@ yarn add react-redux You'll also need to [install Redux](https://redux.js.org/introduction/installation) and [set up a Redux store](https://redux.js.org/recipes/configuring-your-store/) in your app. -If you are using TypeScript, the React Redux types are maintained separately in DefinitelyTyped, but included as a dependency of the `react-redux` package, so they should be installed automatically. If you still need to install them manually, run: - -```bash -npm install @types/react-redux -``` +React-Redux v8 is written in TypeScript, so all types are automatically included. ## API Overview @@ -59,19 +55,19 @@ React Redux includes a `` component, which makes the Redux store ava ```jsx import React from 'react' -import ReactDOM from 'react-dom' +import ReactDOM from 'react-dom/client' import { Provider } from 'react-redux' import store from './store' import App from './App' -const rootElement = document.getElementById('root') -ReactDOM.render( +// As of React 18 +const root = ReactDOM.createRoot(document.getElementById('root')) +root.render( - , - rootElement + ) ``` diff --git a/docs/tutorials/connect.md b/docs/tutorials/connect.md index aaea36a32..9027ebffd 100644 --- a/docs/tutorials/connect.md +++ b/docs/tutorials/connect.md @@ -94,12 +94,12 @@ import TodoApp from './TodoApp' import { Provider } from 'react-redux' import store from './redux/store' -const rootElement = document.getElementById('root') -ReactDOM.render( +// As of React 18 +const root = ReactDOM.createRoot(document.getElementById('root')) +root.render( - , - rootElement + ) ``` diff --git a/docs/tutorials/quick-start.md b/docs/tutorials/quick-start.md index 3e4a8a044..fc22ef1cd 100644 --- a/docs/tutorials/quick-start.md +++ b/docs/tutorials/quick-start.md @@ -65,7 +65,7 @@ Once the store is created, we can make it available to our React components by p ```js title="index.js" import React from 'react' -import ReactDOM from 'react-dom' +import ReactDOM from 'react-dom/client' import './index.css' import App from './App' // highlight-start @@ -73,12 +73,14 @@ import store from './app/store' import { Provider } from 'react-redux' // highlight-end -ReactDOM.render( +// As of React 18 +const root = ReactDOM.createRoot(document.getElementById('root')) + +root.render( // highlight-next-line - , - document.getElementById('root') + ) ``` diff --git a/docs/tutorials/typescript.md b/docs/tutorials/typescript.md index 1734f4301..3758413a0 100644 --- a/docs/tutorials/typescript.md +++ b/docs/tutorials/typescript.md @@ -29,14 +29,20 @@ Welcome to the React Redux TypeScript Quick Start tutorial! **This tutorial will This page focuses on just how to set up the TypeScript aspects . For explanations of what Redux is, how it works, and full examples of how to use Redux, see [the Redux core docs tutorials](https://redux.js.org/tutorials/index). -Redux Toolkit is already written in TypeScript, so its TS type definitions are built in. +Both React-Redux and Redux Toolkit are already written in TypeScript, so their TS type definitions are built in. [React Redux](https://react-redux.js.org) has its type definitions in a separate [`@types/react-redux` typedefs package](https://npm.im/@types/react-redux) on NPM. In addition to typing the library functions, the types also export some helpers to make it easier to write typesafe interfaces between your Redux store and your React components. -As of React Redux v7.2.3, the `react-redux` package has a dependency on `@types/react-redux`, so the type definitions will be automatically installed with the library. Otherwise, you'll need to manually install them yourself (typically `npm install @types/react-redux` ). - The [Redux+TS template for Create-React-App](https://github.com/reduxjs/cra-template-redux-typescript) comes with a working example of these patterns already configured. +:::info + +The recently updated `@types/react@18` major version has changed component definitions to remove having `children` as a prop by default. This causes errors if you have multiple copies of `@types/react` in your project. To fix this, tell your package manager to resolve `@types/react` to a single version. Details: + +https://github.com/facebook/react/issues/24304#issuecomment-1094565891 + +::: + ## Project Setup ### Define Root State and Dispatch Types diff --git a/docs/using-react-redux/usage-with-typescript.md b/docs/using-react-redux/usage-with-typescript.md index 8bf5cb1e2..d0f885a98 100644 --- a/docs/using-react-redux/usage-with-typescript.md +++ b/docs/using-react-redux/usage-with-typescript.md @@ -10,11 +10,15 @@ description: 'Usage > TypeScript: how to correctly type React Redux APIs' # Usage with TypeScript -React Redux itself is currently written in plain JavaScript. However, it works well with static type systems such as TypeScript. +As of React-Redux v8, React-Redux is fully written in TypeScript, and the types are included in the published package. The types also export some helpers to make it easier to write typesafe interfaces between your Redux store and your React components. -The React Redux type definitions are a separate [`@types/react-redux` typedefs package](https://npm.im/@types/react-redux) on NPM. In addition to typing the library functions, the types also export some helpers to make it easier to write typesafe interfaces between your Redux store and your React components. +:::info -**As of React Redux v7.2.3, the `react-redux` package has a dependency on `@types/react-redux`, so the type definitions will be automatically installed with the library**. Otherwise, you'll need to manually install them yourself ( `npm install @types/react-redux` ). +The recently updated `@types/react@18` major version has changed component definitions to remove having `children` as a prop by default. This causes errors if you have multiple copies of `@types/react` in your project. To fix this, tell your package manager to resolve `@types/react` to a single version. Details: + +https://github.com/facebook/react/issues/24304#issuecomment-1094565891 + +::: ## Standard Redux Toolkit Project Setup with TypeScript @@ -120,7 +124,7 @@ const dispatch: AppDispatch = useDispatch() `connect` consists of two functions that are called sequentially. The first function accepts `mapState` and `mapDispatch` as arguments, and returns a second function. The second function accepts the component to be wrapped, and returns a new wrapper component that passes down the props from `mapState` and `mapDispatch`. Normally, both functions are called together, like `connect(mapState, mapDispatch)(MyComponent)`. -As of v7.1.2, the `@types/react-redux` package exposes a helper type, `ConnectedProps`, that can extract the return types of `mapStateToProps` and `mapDispatchToProps` from the first function. This means that if you split the `connect` call into two steps, all of the "props from Redux" can be inferred automatically without having to write them by hand. While this approach may feel unusual if you've been using React-Redux for a while, it does simplify the type declarations considerably. +The package includes a helper type, `ConnectedProps`, that can extract the return types of `mapStateToProps` and `mapDispatchToProps` from the first function. This means that if you split the `connect` call into two steps, all of the "props from Redux" can be inferred automatically without having to write them by hand. While this approach may feel unusual if you've been using React-Redux for a while, it does simplify the type declarations considerably. ```ts import { connect, ConnectedProps } from 'react-redux' diff --git a/website/sidebars.js b/website/sidebars.js index 80cdf87a7..0dbe7c315 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -33,13 +33,7 @@ module.exports = { { type: 'category', label: 'API Reference', - items: [ - 'api/provider', - 'api/hooks', - 'api/connect', - 'api/connect-advanced', - 'api/batch', - ], + items: ['api/provider', 'api/hooks', 'api/connect', 'api/batch'], }, { type: 'category',