Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Pick instead of Omit #8374

Merged
merged 11 commits into from
Dec 10, 2021
42 changes: 42 additions & 0 deletions .github/workflows/format.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Format

on:
push:
branches:
- main

jobs:
format:
runs-on: ubuntu-latest

steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.9.1

- name: Checkout Repository
uses: actions/checkout@v2

- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: 14

- name: Install dependencies
run: yarn install --frozen-lockfile

- name: Format
run: npm run format --if-present

- name: Commit
run: |
git config --local user.email "github-actions@remix.run"
git config --local user.name "Remix Run Bot"

git add .
if [ -z "$(git status --porcelain)" ]; then
echo "💿 no formatting changed"
exit 0
fi
git commit -m "chore: format" -m "formatted $GITHUB_SHA"
git push
echo "💿 pushed formatting changes https://github.com/$GITHUB_REPOSITORY/commit/$(git rev-parse HEAD)"
6 changes: 0 additions & 6 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,6 @@ jobs:
- name: Install dependencies
run: yarn install --frozen-lockfile

- name: Check formatting
run: yarn format:check

- name: Lint
run: yarn lint

- name: Build
run: yarn build

Expand Down
8 changes: 7 additions & 1 deletion .github/workflows/website.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,10 @@ jobs:
url: "${{ secrets.DOCS_REFRESH_URL }}?ref=${{ github.ref }}"
method: "POST"
customHeaders: '{"Authorization": "${{ secrets.DOCS_REFRESH_TOKEN }}"}'
timeout: 60000

- name: Refresh the staging docs
uses: fjogeleit/http-request-action@v1.8.1
with:
url: "${{ secrets.DOCS_STAGING_REFRESH_URL }}?ref=${{ github.ref }}"
method: "POST"
customHeaders: '{"Authorization": "${{ secrets.DOCS_REFRESH_TOKEN }}"}'
6 changes: 6 additions & 0 deletions contributors.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
- Ajayff4
- brockross
- elylucas
- hongji00
- JakubDrozd
- jonkoops
- kentcdodds
- kddnewton
- kkirsche
- markivancho
- mcansh
- noisypigeon
- elylucas
- liuhanqu
- paulsmithkc
- petersendidit
- RobHannay
- shivamsinghchahar
- timdorr
- turansky
Expand Down
77 changes: 75 additions & 2 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ interface BrowserRouterProps {

`<BrowserRouter>` is the recommended interface for running React Router in a web browser. A `<BrowserRouter>` stores the current location in the browser's address bar using clean URLs and navigates using the browser's built-in history stack.

`<BrowserRouter window>` defaults to using the current [document's `defaultView`](https://developer.mozilla.org/en-US/docs/Web/API/Document/defaultView), but it may also be used to track changes to another's window's URL, in an `<iframe>`, for example.
`<BrowserRouter window>` defaults to using the current [document's `defaultView`](https://developer.mozilla.org/en-US/docs/Web/API/Document/defaultView), but it may also be used to track changes to another window's URL, in an `<iframe>`, for example.

```tsx
import * as React from "react";
Expand Down Expand Up @@ -528,7 +528,12 @@ class LoginForm extends React.Component {
<summary>Type declaration</summary>

```tsx
declare function Outlet(): React.ReactElement | null;
interface OutletProps {
context?: unknown;
}
declare function Outlet(
props: OutletProps
): React.ReactElement | null;
```

</details>
Expand Down Expand Up @@ -564,6 +569,74 @@ function App() {
}
```

### `useOutletContext`

<details>
<summary>Type declaration</summary>

```tsx
declare function useOutletContext<
Context = unknown
>(): Context;
```

</details>

Often parent routes manage state or other values you want shared with child routes. You can create your own [context provider](https://reactjs.org/docs/context.html) if you like, but this is such a common situation that it's built-into `<Outlet />`:

```tsx lines=[3]
function Parent() {
const [count, setCount] = React.useState(0);
return <Outlet context={[count, setCount]} />;
}
```

```tsx lines=[2]
function Child() {
const [count, setCount] = useOutletContext();
const increment = () => setCount(c => c + 1);
return <button onClick={increment}>{count}</button>;
}
```

If you're using TypeScript, we recommend the parent component provide a custom hook for accessing the context value. This makes it easier for consumers to get nice typings, control consumers, and know who's consuming the context value. Here's a more realistic example:

```tsx filename=src/routes/dashboard.tsx lines=[12,17-19]
import * as React from "react";
import type { User } from "./types";

type ContextType = { user: User | null };

export default function Dashboard() {
const [user, setUser] = React.useState<User | null>(null);

return (
<div>
<h1>Dashboard</h1>
<Outlet context={user} />
</div>
);
}

export function useUser() {
return useOutletContext<ContextType>();
}
```

```tsx filename=src/routes/dashboard/messages.tsx lines=[1,4]
import { useUser } from "../dashboard";

export default function DashboardMessages() {
const user = useUser();
return (
<div>
<h2>Messages</h2>
<p>Hello, {user.name}!</p>
</div>
);
}
```

### `<Router>`

<details>
Expand Down
2 changes: 1 addition & 1 deletion docs/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Before you can contribute to the codebase, you will need to fork the repo. This
- All new features, bug-fixes, or **anything that touches `react-router` code** should be branched off of and merged into the `dev` branch
- Changes that only touch documentation can be branched off of and merged into the `main` branch

The following steps will get you setup to contribute changes to this repo:
The following steps will get you set up to contribute changes to this repo:

1. Fork the repo (click the <kbd>Fork</kbd> button at the top right of [this page](https://github.com/remix-run/react-router))
2. Clone your fork locally
Expand Down
10 changes: 5 additions & 5 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ In React Router v6 we switched from using v5's `<Route component>` and `<Route r

For starters, we see React itself taking the lead here with the `<Suspense fallback={<Spinner />}>` API. The `fallback` prop takes a React **element**, not a **component**. This lets you easily pass whatever props you want to your `<Spinner>` from the component that renders it.

Using elements instead of components means we don't have to provide a `passProps`-style API so you can get the props you need to your elements. For example, in a component-based API there is no good way to pass props to the `<Profile>` element that is rendered when `<Route path=":userId" component={Profile} />` matches. Most React libraries who take this approach end up with either an API like `<Route component={Profile} passProps={{ animate: true }} />` or use a render prop or higher-order component.
Using elements instead of components means we don't have to provide a `passProps`-style API, so you can get the props you need to your elements. For example, in a component-based API there is no good way to pass props to the `<Profile>` element that is rendered when `<Route path=":userId" component={Profile} />` matches. Most React libraries who take this approach end up with either an API like `<Route component={Profile} passProps={{ animate: true }} />` or use a render prop or higher-order component.

Also, `Route`'s rendering API in v5 was rather large. As we worked on v4/5, the conversation went something like this:

Expand Down Expand Up @@ -128,7 +128,7 @@ In v4 we would have just left the path prop off a route. In v5 we would have wra

## `<Route>` doesn't render? How do I compose?

In v5 the `<Route>` component was just a normal component that was like an `if` statement that rendered when the URL matched it's path. In v6, a `<Route>` element doesn't actually ever render, it's simply there for configuration.
In v5 the `<Route>` component was just a normal component that was like an `if` statement that rendered when the URL matched its path. In v6, a `<Route>` element doesn't actually ever render, it's simply there for configuration.

In v5, since routes were just components, `MyRoute` will be rendered when the path is "/my-route".

Expand All @@ -146,7 +146,7 @@ let MyRoute = ({ element, ...rest }) => {
};
```

In v6, however, the `<Route>` is only used for it's props, so the following code will never render `<p>Hello!</p>` because `<MyRoute>` has no path that `<Routes>` can see:
In v6, however, the `<Route>` is only used for its props, so the following code will never render `<p>Hello!</p>` because `<MyRoute>` has no path that `<Routes>` can see:

```tsx bad filename=v6-wrong.js
let App = () => (
Expand Down Expand Up @@ -196,7 +196,7 @@ function MatchPath({ path, Comp }) {

## How do I nest routes deep in the tree?

In v5 you could render a `<Route>` or `<Switch>` anywhere you want. You can keep doing the very same thing but you need to use `<Routes>` (`<Route>` without an 's' will not work). We call these "Descendant `<Routes>`".
In v5 you could render a `<Route>` or `<Switch>` anywhere you want. You can keep doing the very same thing, but you need to use `<Routes>` (`<Route>` without an 's' will not work). We call these "Descendant `<Routes>`".

It might have looked like this in v5

Expand Down Expand Up @@ -391,7 +391,7 @@ function App() {
}
```

In fact, the v5 version has all sorts of problems if your routes aren't ordered _just right_. V6 competely eliminates this problem.
In fact, the v5 version has all sorts of problems if your routes aren't ordered _just right_. V6 completely eliminates this problem.

**Remix Users**

Expand Down
6 changes: 3 additions & 3 deletions docs/getting-started/concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ Here are some words we use a lot when we talk about React Router. The rest of th

- <a id="history-stack">**History Stack**</a> - As the user navigates, the browser keeps track of each [location](#location) in a stack. If you click and hold the back button in a browser you can see the browser's history stack right there.

- <a id="csr">**Client Side Routing (CSR)**</a> - A plain HTML document can link to other documents and the browser handles the [history stack](#history-stack) itself. Client Side Routing enables developers to manipulate the browser history stack without making document request to the server.
- <a id="csr">**Client Side Routing (CSR)**</a> - A plain HTML document can link to other documents and the browser handles the [history stack](#history-stack) itself. Client Side Routing enables developers to manipulate the browser history stack without making a document request to the server.

- <a id="history-object">**History**</a> - An object allows React Router to subscribe to changes in the [URL](#url) as well as providing APIs to manipulate the browser [history stack](#history-stack) programmatically.
- <a id="history-object">**History**</a> - An object that allows React Router to subscribe to changes in the [URL](#url) as well as providing APIs to manipulate the browser [history stack](#history-stack) programmatically.

- <a id="history-action">**History Action**</a> - One of `POP`, `PUSH`, or `REPLACE`. Users can arrive at a [URL](#url) for one of these three reasons. A push when a new entry is added to the history stack (typically a link click or the programmer forced a navigation). A replace is similar except it replaces the current entry on the stack instead of pushing a new one. Finally, a pop happens when the user clicks the back or forward buttons in the browser chrome.

Expand Down Expand Up @@ -230,7 +230,7 @@ You can think about `location.state` just like `location.hash` or `location.sear

A couple great use-cases for location state are:

- Telling the next page where the user came from and branching the UI. The most popular implementation here is the showing a record in a modal if the user clicked on an item in a grid view, but if they show up to the URL directly, show the record in it's own layout (pinterest, old instagram).
- Telling the next page where the user came from and branching the UI. The most popular implementation here is the showing a record in a modal if the user clicked on an item in a grid view, but if they show up to the URL directly, show the record in its own layout (pinterest, old instagram).
- Sending a partial record from a list to the next screen so it can render the partial data immediately and then fetching the rest of the data afterward.

You set location state in two ways: on `<Link>` or `navigate`:
Expand Down
6 changes: 3 additions & 3 deletions docs/getting-started/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ function About() {
}
```

Go ahead and start your app by running `npm start`, and you should see the `Home` route when your app starts running. Click the "About" link to see your `<About>` route, and voila! You've successfully set up React Router using Create React App! 🥳
Go ahead and start your app by running `npm start`, and you should see the `Home` route when your app starts running. Click the "About" link to see your `<About>` route, and voilà! You've successfully set up React Router using Create React App! 🥳

When it's time to deploy your app to production, be sure to follow [Create React App's instructions](https://create-react-app.dev/docs/deployment#serving-apps-with-client-side-routing) on deploying with React Router to be sure your server is configured correctly.

Expand Down Expand Up @@ -163,7 +163,7 @@ ReactDOM.render(
);
```

In your `index.html`, create the root div in the document body above the script tag. It's also helpful to provide a `noscript` fallback message for users who may disabled JavaScript, unless you plan on server-rendering your app later.
In your `index.html`, create the root div in the document body above the script tag. It's also helpful to provide a `noscript` fallback message for users who may have disabled JavaScript, unless you plan on server-rendering your app later.

```html
<body>
Expand Down Expand Up @@ -231,7 +231,7 @@ function About() {
export default App;
```

Now start your app by running `npm start`, and you should see the `Home` route when your app starts running. Click the "About" link to see your `About` route, and voila! You successfully set up React Router using Parcel! 🥳
Now start your app by running `npm start`, and you should see the `Home` route when your app starts running. Click the "About" link to see your `About` route, and voilà! You successfully set up React Router using Parcel! 🥳

## Webpack

Expand Down
6 changes: 3 additions & 3 deletions docs/getting-started/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ function SentInvoices() {

The nested url segments map to nested component trees. This is perfect for creating UI that has persistent navigation in layouts with an inner section that changes with the URL. If you look around the web you'll notice many websites (and especially web apps) have multiple levels of layout nesting.

Here's a another example of a root layout with navigation that persists while the inner page swaps out with the URL:
Here's another example of a root layout with navigation that persists while the inner page swaps out with the URL:

```tsx
import {
Expand Down Expand Up @@ -311,7 +311,7 @@ function App() {

Now at "/" the `<Activity>` element will render inside the outlet.

You can have an index route at any level of the route hierarchy that will render when the parent matches but none of it's other children do.
You can have an index route at any level of the route hierarchy that will render when the parent matches but none of its other children do.

```tsx
function App() {
Expand Down Expand Up @@ -435,7 +435,7 @@ function App() {

## Descendant `<Routes>`

You can render [a `<Routes>` element](../api.md#routes) anywhere you need one, including deep within the component tree of another `<Routes>`. These will work just the same as any other `<Routes>`, except they will automatically build on the path of the route that rendered them. If you do this, _make sure to put a \* at the end of the parent route's path_. Otherwise the parent route won't match the URL when it is longer than the parent route's path, and your descendant `<Routes>` won't ever show up.
You can render [a `<Routes>` element](../api.md#routes) anywhere you need one, including deep within the component tree of another `<Routes>`. These will work just the same as any other `<Routes>`, except they will automatically build on the path of the route that rendered them. If you do this, _make sure to put a \* at the end of the parent route's path_. Otherwise, the parent route won't match the URL when it is longer than the parent route's path, and your descendant `<Routes>` won't ever show up.

```tsx [5]
function App() {
Expand Down
6 changes: 3 additions & 3 deletions docs/getting-started/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Then install React Router dependencies:

```sh
cd router-tutorial
npm add react-router-dom@6 history@5
npm install react-router-dom@6 history@5
```

Then edit your App.js to be pretty boring:
Expand All @@ -80,7 +80,7 @@ const rootElement = document.getElementById("root");
render(<App />, rootElement);
```

Finally start your app:
Finally, start your app:

```sh
# probably this
Expand Down Expand Up @@ -794,7 +794,7 @@ Most of the time the URL changes is in response to the user clicking a link. But

Let's add a button that marks the invoice as paid and then navigates to the index route.

First you can copy paste this function that deletes an invoice from our fake data store:
First you can copy and paste this function that deletes an invoice from our fake data store:

```js filename=src/data.js
export function deleteInvoice(number) {
Expand Down