From 02a061f1feca52f5b298877fc215f71fd5edbbb0 Mon Sep 17 00:00:00 2001 From: sveinpg Date: Sat, 6 Oct 2018 00:16:34 +0200 Subject: [PATCH 1/4] #1031 Set up basic docusaurus structure --- docusaurus/.dockerignore | 2 + docusaurus/.gitignore | 12 + docusaurus/Dockerfile | 10 + docusaurus/docker-compose.yml | 18 + docusaurus/docs/GettingStarted.md | 492 +++++++++++++++++ docusaurus/docs/README.md | 10 + docusaurus/docs/api.md | 501 ++++++++++++++++++ docusaurus/docs/api/Provider.md | 75 +++ docusaurus/docs/troubleshooting.md | 86 +++ docusaurus/website/README.md | 193 +++++++ docusaurus/website/core/Footer.js | 79 +++ docusaurus/website/package.json | 14 + docusaurus/website/pages/en/index.js | 120 +++++ docusaurus/website/sidebars.json | 5 + docusaurus/website/siteConfig.js | 84 +++ docusaurus/website/static/css/custom.css | 16 + .../website/static/img/favicon/favicon.ico | Bin 0 -> 4286 bytes docusaurus/website/static/img/redux.svg | 7 + 18 files changed, 1724 insertions(+) create mode 100644 docusaurus/.dockerignore create mode 100644 docusaurus/.gitignore create mode 100644 docusaurus/Dockerfile create mode 100644 docusaurus/docker-compose.yml create mode 100644 docusaurus/docs/GettingStarted.md create mode 100644 docusaurus/docs/README.md create mode 100644 docusaurus/docs/api.md create mode 100644 docusaurus/docs/api/Provider.md create mode 100644 docusaurus/docs/troubleshooting.md create mode 100644 docusaurus/website/README.md create mode 100644 docusaurus/website/core/Footer.js create mode 100644 docusaurus/website/package.json create mode 100755 docusaurus/website/pages/en/index.js create mode 100644 docusaurus/website/sidebars.json create mode 100644 docusaurus/website/siteConfig.js create mode 100644 docusaurus/website/static/css/custom.css create mode 100644 docusaurus/website/static/img/favicon/favicon.ico create mode 100644 docusaurus/website/static/img/redux.svg diff --git a/docusaurus/.dockerignore b/docusaurus/.dockerignore new file mode 100644 index 000000000..27d2dae2b --- /dev/null +++ b/docusaurus/.dockerignore @@ -0,0 +1,2 @@ +*/node_modules +*.log diff --git a/docusaurus/.gitignore b/docusaurus/.gitignore new file mode 100644 index 000000000..5395ea795 --- /dev/null +++ b/docusaurus/.gitignore @@ -0,0 +1,12 @@ +.DS_Store + +node_modules + +lib/core/metadata.js +lib/core/MetadataBlog.js + +website/translated_docs +website/build/ +website/yarn.lock +website/node_modules +website/i18n/* diff --git a/docusaurus/Dockerfile b/docusaurus/Dockerfile new file mode 100644 index 000000000..d369844d5 --- /dev/null +++ b/docusaurus/Dockerfile @@ -0,0 +1,10 @@ +FROM node:8.11.4 + +WORKDIR /app/website + +EXPOSE 3000 35729 +COPY ./docs /app/docs +COPY ./website /app/website +RUN yarn install + +CMD ["yarn", "start"] diff --git a/docusaurus/docker-compose.yml b/docusaurus/docker-compose.yml new file mode 100644 index 000000000..6711192ae --- /dev/null +++ b/docusaurus/docker-compose.yml @@ -0,0 +1,18 @@ +version: "3" + +services: + docusaurus: + build: . + ports: + - 3000:3000 + - 35729:35729 + volumes: + - ./docs:/app/docs + - ./website/blog:/app/website/blog + - ./website/core:/app/website/core + - ./website/i18n:/app/website/i18n + - ./website/pages:/app/website/pages + - ./website/static:/app/website/static + - ./website/sidebars.json:/app/website/sidebars.json + - ./website/siteConfig.js:/app/website/siteConfig.js + working_dir: /app/website diff --git a/docusaurus/docs/GettingStarted.md b/docusaurus/docs/GettingStarted.md new file mode 100644 index 000000000..7040aca61 --- /dev/null +++ b/docusaurus/docs/GettingStarted.md @@ -0,0 +1,492 @@ +--- +id: getting-started +title: Getting started +sidebar_label: Getting started +--- + +[React-Redux](https://github.com/reduxjs/react-redux) is the official [React](https://reactjs.org/) binding for [Redux](https://redux.js.org/). It lets your React components read data from a Redux store, and dispatch actions to the store to update data. + +## Installation + +To use React-Redux with your React app: + +```bash +npm install --save react-redux +``` + +or + +``` +yarn add react-redux +``` + + + +## `` and `connect` + +React-Redux consists of two main pieces. The first is a component called ``, which makes the Redux store available to the rest of your app: + +```js +import React from "react"; +import ReactDOM from "react-dom"; + +import { Provider } from "react-redux"; +import store from "./store"; + +import App from "./App"; + +const rootElement = document.getElementById("root"); +ReactDOM.render( + + + , + rootElement +); +``` + +The second piece is a function called `connect()`, which encapsulates the process of talking to the store. + +It enables you to: + +* Read data from the Redux `store` into your app’s connected components as props +* Dispatch actions to your `store` from any of your app’s connected components + +Correspondingly, the `connect` function takes two arguments, both optional: + +* `mapStateToProps`: called every time the store state changes. It receives the entire store state, and should return an object of data this component needs. + +* `mapDispatchToProps`: this parameter can either be a function, or an object. + * If it’s a function, it will be called once on component creation. It will receive `dispatch` as an argument, and should return an object full of functions that use `dispatch` to dispatch actions. + * If it’s an object full of action creators, each action creator will be turned into a prop function that automatically dispatches its action when called. **Note**: We recommend using this “object shorthand” form. + +Normally, you’ll call `connect` in this way: + +```jsx +const mapStateToProps = (state, ownProps) => ({ + // ... computed data from state and optionally ownProps +}); + +const mapDispatchToProps = { + // ... normally is an object full of action creators +}; + +// `connect` returns a new function that accepts the component to wrap: +const connectToStore = connect(mapStateToProps, mapDispatchToProps); +// and that function returns the connected, wrapper component: +const ConnectedComponent = connectToStore(Component); + +// We normally do both in one step, like this: +connect(mapStateToProps, mapDispatchToProps)(Component); +``` + +## A Todo List Example + +To see this in practice, we’ll show a step-by-step example by creating a todo list app using React-Redux. + +**Jump to** + +* 🤞 [Just show me the code](https://codesandbox.io/s/9on71rvnyo) +* 👆 [Providing the store](#providing-the-store) +* ✌️ [Common Ways of Calling Connect](#common-ways-of-calling-connect) + +**The React UI Components** + +We have implemented our React UI components as follows: + +* `TodoApp` is the entry component for our app. It renders the header, the `AddTodo`, `TodoList`, and `VisibilityFilters` components. +* `AddTodo` is the component that allows a user to input a todo item and add to the list upon clicking its “Add Todo” button: + * It uses a controlled input that sets state upon `onChange`. + * When the user clicks on the “Add Todo” button, it dispatches the action (that we will provide using React-Redux) to add the todo to the store. +* `TodoList` is the component that renders the list of todos: + * It renders the filtered list of todos when one of the `VisibilityFilters` is selected. +* `Todo` is the component that renders a single todo item: + * It renders the todo content, and shows that a todo is completed by crossing it out. + * It dispatches the action to toggle the todo's complete status upon `onClick`. +* `VisibilityFilters` renders a simple set of filters: _all_, _completed_, and _incomplete._ Clicking on each one of them filters the todos: + * It accepts an `activeFilter` prop from the parent that indicates which filter is currently selected by the user. An active filter is rendered with an underscore. + * It dispatches the `setFilter` action to update the selected filter. +* `constants` holds the constants data for our app. +* And finally `index` renders our app to the DOM. + +
+ +**The Redux Store** + +The Redux portion of the application has been set up using the [patterns recommended in the Redux docs](https://redux.js.org): + +* Store + * `todos`: A normalized reducer of todos. It contains a `byIds` map of all todos and a `allIds` that contains the list of all ids. + * `visibilityFilters`: A simple string `all`, `completed`, or `incomplete`. +* Action Creators + * `addTodo` creates the action to add todos. It takes a single string variable `content` and returns an `ADD_TODO` action with `payload` containing a self-incremented `id` and `content` + * `toggleTodo` creates the action to toggle todos. It takes a single number variable `id` and returns a `TOGGLE_TODO` action with `payload` containing `id` only + * `setFilter` creates the action to set the app’s active filter. It takes a single string variable `filter` and returns a `SET_FILTER` action with `payload` containing the `filter` itself +* Reducers + * The `todos` reducer + * Appends the `id` to its `allIds` field and sets the todo within its `byIds` field upon receiving the `ADD_TODO` action + * Toggles the `completed` field for the todo upon receiving the `TOGGLE_TODO` action + * The `visibilityFilters` reducer sets its slice of store to the new filter it receives from the `SET_FILTER` action payload +* Action Types + * We use a file `actionTypes.js` to hold the constants of action types to be reused +* Selectors + * `getTodoList` returns the `allIds` list from the `todos` store + * `getTodoById` finds the todo in the store given by `id` + * `getTodos` is slightly more complex. It takes all the `id`s from `allIds`, finds each todo in `byIds`, and returns the final array of todos + * `getTodosByVisibilityFilter` filters the todos according to the visibility filter + +You may check out [this CodeSandbox](https://codesandbox.io/s/6vwyqrpqk3) for the source code of the UI components and the unconnected Redux store described above. + +
+ +We will now show how to connect this store to our app using React-Redux. + +### Providing the Store + +First we need to make the `store` available to our app. To do this, we wrap our app with the `` API provided by React-Redux. + +```jsx +// index.js +import React from "react"; +import ReactDOM from "react-dom"; +import TodoApp from "./TodoApp"; + +import { Provider } from "react-redux"; +import store from "./redux/store"; + +const rootElement = document.getElementById("root"); +ReactDOM.render( + + + , + rootElement +); +``` + +Notice how our `` is now wrapped with the `` with `store` passed in as a prop. + +![](https://i.imgur.com/LV0XvwA.png) + +### Connecting the Components + +Our components need to read values from the Redux store (and re-read the values when the store updates). They also need to dispatch actions to trigger updates. + +`connect` takes in two parameters. The first one allows you to define which pieces of data from the store are needed by this component. The second one allows you to indicate which actions that component might dispatch. By convention, they are called `mapStateToProps` and `mapDispatchToProps`, respectively. The return of this call is another function that accepts the component on a second call. This is an example of a pattern called [_higher order components_](https://medium.com/@franleplant/react-higher-order-components-in-depth-cf9032ee6c3e). + +Let’s work on `` first. It needs to trigger changes to the `store` to add new todos. Therefore, it needs to be able to `dispatch` actions to the store. Here’s how we do it. + +Our `addTodo` action creator looks like this: + +```JavaScript +// redux/actions.js +import { ADD_TODO } from './actionTypes'; + +let nextTodoId = 0; +export const addTodo = content => ({ + type: ADD_TODO, + payload: { + id: ++nextTodoId, + content + } +}); + +// ... other actions +``` + +By passing it to `connect`, our component receives it as a prop, and it will automatically dispatch the action when it’s called. + +```jsx +// components/AddTodo.js + +// ... other imports +import { connect } from "react-redux"; +import { addTodo } from "../redux/actions"; + +class AddTodo extends React.Component { + // ... component implementation +} + +export default connect(null, { addTodo })(AddTodo); +``` + +Notice now that `` is wrapped with a parent component called ``. Meanwhile, `` now gains one prop: the `addTodo` action. + +![](https://i.imgur.com/u6aXbwl.png) + +We also need to implement the `handleAddTodo` function to let it dispatch the `addTodo` action and reset the input + +```jsx +// components/AddTodo.js + +import React from "react"; +import { connect } from "react-redux"; +import { addTodo } from "../redux/actions"; + +class AddTodo extends React.Component { + // ... + + handleAddTodo = () => { + // dispatches actions to add todo + this.props.addTodo(this.state.input); + + // sets state back to empty string + this.setState({ input: "" }); + }; + + render() { + return ( +
+ this.updateInput(e.target.value)} + value={this.state.input} + /> + +
+ ); + } +} + +export default connect(null, { addTodo })(AddTodo); +``` + +Now our `` is connected to the store. When we add a todo it would dispatch an action to change the store. We are not seeing it in the app because the other components are not connected yet. If you have the Redux DevTools Extension hooked up, you should see the action being dispatched: + +![](https://i.imgur.com/kHvkqhI.png) + +You should also see that the store has changed accordingly: + +![](https://i.imgur.com/yx27RVC.png) + +The `` component is responsible for rendering the list of todos. Therefore, it needs to read data from the store. We enable it by calling `connect` with the `mapStateToProps` parameter, a function describing which part of the data we need from the store. + +Our `` component takes the todo item as props. We have this information from the `byIds` field of the `todos`. However, we also need the information from the `allIds` field of the store indicating which todos and in what order they should be rendered. Our `mapStateToProps` function may look like this: + +```jsx +// components/TodoList.js + +// ...other imports +import { connect } from "react-redux"; + +const TodoList = // ... UI component implementation + +const mapStateToProps = state => { + const { byIds, allIds } = state.todos || {}; + const todos = + allIds && allIds.length + ? allIds.map(id => (byIds ? { ...byIds[id], id } : null)) + : null; + return { todos }; +}; + +export default connect(mapStateToProps)(TodoList); +``` + +Luckily we have a selector that does exactly this. We may simply import the selector and use it here. + +```jsx +// redux/selectors.js + +export const getTodosState = store => store.todos; + +export const getTodoList = store => + getTodosState(store) ? getTodosState(store).allIds : []; + +export const getTodoById = (store, id) => + getTodoState(store) ? { ...getTodosState(store).byIds[id], id } : {}; + +/** + * example of a slightly more complex selector + * select from store combining information from multiple reducers + */ +export const getTodos = store => + getTodoList(store).map(id => getTodoById(store, id)); +``` + +```jsx +// components/TodoList.js + +// ...other imports +import { connect } from "react-redux"; +import { getTodos } from "../redux/selectors"; + +const TodoList = // ... UI component implementation + +export default connect(state => ({ todos: getTodos(state) }))(TodoList); +``` + +We recommend encapsulating any complex lookups or computations of data in selector functions. In addition, you can further optimize the performance by using [Reselect](https://github.com/reduxjs/reselect) to write “memoized” selectors that can skip unnecessary work. (See [the Redux docs page on Computing Derived Data](https://redux.js.org/recipes/computingderiveddata#sharing-selectors-across-multiple-components) and the blog post [Idiomatic Redux: Using Reselect Selectors for Encapsulation and Performance](https://blog.isquaredsoftware.com/2017/12/idiomatic-redux-using-reselect-selectors/) for more information on why and how to use selector functions.) + +Now that our `` is connected to the store. It should receive the list of todos, map over them, and pass each todo to the `` component. `` will in turn render them to the screen. Now try adding a todo. It should come up on our todo list! + +![](https://i.imgur.com/N68xvrG.png) + +We will connect more components. Before we do this, let’s pause and learn a bit more about `connect` first. + +### Common ways of calling `connect` + +Depending on what kind of components you are working with, there are different ways of calling `connect` , with the most common ones summarized as below: + +| | Do Not Subscribe to the Store | Subscribe to the Store | +| ----------------------------- | ---------------------------------------------- | --------------------------------------------------------- | +| Do Not Inject Action Creators | `connect()(Component)` | `connect(mapStateToProps)(Component)` | +| Inject Action Creators | `connect(null, mapDispatchToProps)(Component)` | `connect(mapStateToProps, mapDispatchToProps)(Component)` | + +#### Do not subscribe to the store and do not inject action creators + +If you call `connect` without providing any arguments, your component will: + +* _not_ re-render when the store changes +* receive `props.dispatch` that you may use to manually dispatch action + +```jsx +// ... Component +export default connect()(Component); // Component will receive `dispatch` (just like our !) +``` + +#### Subscribe to the store and do not inject action creators + +If you call `connect` with only `mapStateToProps`, your component will: + +* subscribe to the values that `mapStateToProps` extracts from the store, and re-render only when those values have changed +* receive `props.dispatch` that you may use to manually dispatch action + +```jsx +// ... Component +const mapStateToProps = state => state.partOfState; +export default connect(mapStateToProps)(Component); +``` + +#### Do not subscribe to the store and inject action creators + +If you call `connect` with only `mapDispatchToProps`, your component will: + +* _not_ re-render when the store changes +* receive each of the action creators you inject with `mapDispatchToProps` as props and automatically dispatch the actions upon being called + +```jsx +import { addTodo } from "./actionCreators"; +// ... Component +export default connect(null, { addTodo })(Component); +``` + +#### Subscribe to the store and inject action creators + +If you call `connect` with both `mapStateToProps` and `mapDispatchToProps`, your component will: + +* subscribe to the values that `mapStateToProps` extracts from the store, and re-render only when those values have changed +* receive all of the action creators you inject with `mapDispatchToProps` as props and automatically dispatch the actions upon being called. + +```jsx +import * as actionCreators from "./actionCreators"; +// ... Component +const mapStateToProps = state => state.partOfState; +export default connect(mapStateToProps, actionCreators)(Component); +``` + +These four cases cover the most basic usages of `connect`. To read more about `connect`, continue reading our [API section](./api.md) that explains it in more detail. + + + +--- + +Now let’s connect the rest of our ``. + +How should we implement the interaction of toggling todos? A keen reader might already have an answer. If you have your environment set up and have followed through up until this point, now is a good time to leave it aside and implement the feature by yourself. There would be no surprise that we connect our `` to dispatch `toggleTodo` in a similar way: + +```jsx +// components/Todo.js + +// ... other imports +import { connect } from "react-redux"; +import { toggleTodo } from "../redux/actions"; + +const Todo = // ... component implementation + +export default connect( + null, + { toggleTodo } +)(Todo); +``` + +Now our todo’s can be toggled complete. We’re almost there! + +![](https://i.imgur.com/4UBXYtj.png) + +Finally, let’s implement our `VisibilityFilters` feature. + +The `` component needs to be able to read from the store which filter is currently active, and dispatch actions to the store. Therefore, we need to pass both a `mapStateToProps` and `mapDispatchToProps`. The `mapStateToProps` here can be a simple accessor of the `visibilityFilter` state. And the `mapDispatchToProps` will contain the `setFilter` action creator. + +```jsx +// components/VisibilityFilters.js + +// ... other imports +import { connect } from "react-redux"; +import { setFilter } from "../redux/actions"; + +const VisibilityFilters = // ... component implementation + +const mapStateToProps = state => { + return { activeFilter: state.visibilityFilter }; +}; +export default connect( + mapStateToProps, + { setFilter } +)(VisibilityFilters); +``` + +Meanwhile, we also need to update our `` component to filter todos according to the active filter. Previously the `mapStateToProps` we passed to the `` `connect` function call was simply the selector that selects the whole list of todos. Let’s write another selector to help filtering todos by their status. + +```js +// redux/selectors.js + +// ... other selectors + +export const getTodosByVisibilityFilter = (store, visibilityFilter) => { + const allTodos = getTodos(store); + switch (visibilityFilter) { + case VISIBILITY_FILTERS.COMPLETED: + return allTodos.filter(todo => todo.completed); + case VISIBILITY_FILTERS.INCOMPLETE: + return allTodos.filter(todo => !todo.completed); + case VISIBILITY_FILTERS.ALL: + default: + return allTodos; + } +}; +``` + +And connecting to the store with the help of the selector: + +```jsx +// components/TodoList.js + +// ... + +const mapStateToProps = state => { + const { visibilityFilter } = state; + const todos = getTodosByVisibilityFilter(state, visibilityFilter); + return { todos }; +}; + +export default connect(mapStateToProps)(TodoList); +``` + +Now we've finished a very simple example of a todo app with React-Redux. All our components are connected! Isn't that nice? 🎉🎊 + +![](https://i.imgur.com/ONqer2R.png) + +## Links + +* [Usage with React](https://redux.js.org/basics/usagewithreact) +* [Using the React-Redux Bindings](https://blog.isquaredsoftware.com/presentations/workshops/redux-fundamentals/react-redux.html) +* [Higher Order Components in Depth](https://medium.com/@franleplant/react-higher-order-components-in-depth-cf9032ee6c3e) + +* [Computing Derived Data](https://redux.js.org/recipes/computingderiveddata#sharing-selectors-across-multiple-components) +* [Idiomatic Redux: Using Reselect Selectors for Encapsulation and Performance](https://blog.isquaredsoftware.com/2017/12/idiomatic-redux-using-reselect-selectors/) + +## Get More Help + +* [Reactiflux](https://www.reactiflux.com) Redux channel +* [StackOverflow](https://stackoverflow.com/questions/tagged/react-redux) +* [GitHub Issues](https://github.com/reduxjs/react-redux/issues/) diff --git a/docusaurus/docs/README.md b/docusaurus/docs/README.md new file mode 100644 index 000000000..c4258c954 --- /dev/null +++ b/docusaurus/docs/README.md @@ -0,0 +1,10 @@ +# Table of Contents + + + +- [Getting Started: adding React-Redux to a React todo app](./GettingStarted.md) +- [API](api.md#api) + - [``](api.md#provider-store) + - [`connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])`](api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options) + - [`connectAdvanced(selectorFactory, [connectOptions])`](api.md#connectadvancedselectorfactory-connectoptions) +- [Troubleshooting](troubleshooting.md#troubleshooting) diff --git a/docusaurus/docs/api.md b/docusaurus/docs/api.md new file mode 100644 index 000000000..67f8d9c4b --- /dev/null +++ b/docusaurus/docs/api.md @@ -0,0 +1,501 @@ +--- +id: api +title: Api +sidebar_label: Api +--- + + + +### `` + +Makes the Redux store available to the `connect()` calls in the component hierarchy below. Normally, you can’t use `connect()` without wrapping a parent or ancestor component in ``. + +If you _really_ need to, you can manually pass `store` as a prop to every `connect()`ed component, but we only recommend to do this for stubbing `store` in unit tests, or in non-fully-React codebases. Normally, you should just use ``. + +#### Props + +* `store` (_[Redux Store](https://redux.js.org/api-reference/store)_): The single Redux store in your application. +* `children` (_ReactElement_) The root of your component hierarchy. + +#### Example + +##### Vanilla React + +```js +ReactDOM.render( + + + , + rootEl +); +``` + +##### React Router + +```js +ReactDOM.render( + + + + + + + + , + document.getElementById("root") +); +``` + + + +### `connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])` + +Connects a React component to a Redux store. `connect` is a facade around `connectAdvanced`, providing a convenient API for the most common use cases. + +It does not modify the component class passed to it; instead, it _returns_ a new, connected component class for you to use. + + + +#### Arguments + +* [`mapStateToProps(state, [ownProps]): stateProps`] \(_Function_): If this argument is specified, the new component will subscribe to Redux store updates. This means that any time the store is updated, `mapStateToProps` will be called. The results of `mapStateToProps` must be a plain object, which will be merged into the component’s props. If you don't want to subscribe to store updates, pass `null` or `undefined` in place of `mapStateToProps`. + + If your `mapStateToProps` function is declared as taking two parameters, it will be called with the store state as the first parameter and the props passed to the connected component as the second parameter, and will also be re-invoked whenever the connected component receives new props as determined by shallow equality comparisons. (The second parameter is normally referred to as `ownProps` by convention.) + + > Note: in advanced scenarios where you need more control over the rendering performance, `mapStateToProps()` can also return a function. In this case, _that_ function will be used as `mapStateToProps()` for a particular component instance. This allows you to do per-instance memoization. You can refer to [#279](https://github.com/reduxjs/react-redux/pull/279) and the tests it adds for more details. Most apps never need this. + + > The `mapStateToProps` function's first argument is the entire Redux store’s state and it returns an object to be passed as props. It is often called a **selector**. Use [reselect](https://github.com/reduxjs/reselect) to efficiently compose selectors and [compute derived data](https://redux.js.org/recipes/computing-derived-data). + +* [`mapDispatchToProps(dispatch, [ownProps]): dispatchProps`] \(_Object_ or _Function_): If an object is passed, each function inside it is assumed to be a Redux action creator. An object with the same function names, but with every action creator wrapped into a `dispatch` call so they may be invoked directly, will be merged into the component’s props. + + If a function is passed, it will be given `dispatch` as the first parameter. It’s up to you to return an object that somehow uses `dispatch` to bind action creators in your own way. (Tip: you may use the [`bindActionCreators()`](https://redux.js.org/api-reference/bindactioncreators) helper from Redux.) + + If your `mapDispatchToProps` function is declared as taking two parameters, it will be called with `dispatch` as the first parameter and the props passed to the connected component as the second parameter, and will be re-invoked whenever the connected component receives new props. (The second parameter is normally referred to as `ownProps` by convention.) + + If you do not supply your own `mapDispatchToProps` function or object full of action creators, the default `mapDispatchToProps` implementation just injects `dispatch` into your component’s props. + + > Note: in advanced scenarios where you need more control over the rendering performance, `mapDispatchToProps()` can also return a function. In this case, _that_ function will be used as `mapDispatchToProps()` for a particular component instance. This allows you to do per-instance memoization. You can refer to [#279](https://github.com/reduxjs/react-redux/pull/279) and the tests it adds for more details. Most apps never need this. + +* [`mergeProps(stateProps, dispatchProps, ownProps): props`] \(_Function_): If specified, it is passed the result of `mapStateToProps()`, `mapDispatchToProps()`, and the parent `props`. The plain object you return from it will be passed as props to the wrapped component. You may specify this function to select a slice of the state based on props, or to bind action creators to a particular variable from props. If you omit it, `Object.assign({}, ownProps, stateProps, dispatchProps)` is used by default. + +* [`options`] _(Object)_ If specified, further customizes the behavior of the connector. In addition to the options passable to `connectAdvanced()` (see those below), `connect()` accepts these additional options: + * [`pure`] _(Boolean)_: If true, `connect()` will avoid re-renders and calls to `mapStateToProps`, `mapDispatchToProps`, and `mergeProps` if the relevant state/props objects remain equal based on their respective equality checks. 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. Default value: `true` + * [`areStatesEqual`] _(Function)_: When pure, compares incoming store state to its previous value. Default value: `strictEqual (===)` + * [`areOwnPropsEqual`] _(Function)_: When pure, compares incoming props to its previous value. Default value: `shallowEqual` + * [`areStatePropsEqual`] _(Function)_: When pure, compares the result of `mapStateToProps` to its previous value. Default value: `shallowEqual` + * [`areMergedPropsEqual`] _(Function)_: When pure, compares the result of `mergeProps` to its previous value. Default value: `shallowEqual` + * [`storeKey`] _(String)_: The key of the context from where to read the store. You probably only need this if you are in the inadvisable position of having multiple stores. Default value: `'store'` + + + +##### The arity of mapStateToProps and mapDispatchToProps determines whether they receive ownProps + +> Note: `ownProps` **is not passed** to `mapStateToProps` and `mapDispatchToProps` if the formal definition of the function contains one mandatory parameter (function has length 1). For example, functions defined like below won't receive `ownProps` as the second argument. + +```javascript +function mapStateToProps(state) { + console.log(state); // state + console.log(arguments[1]); // undefined +} +``` + +```javascript +const mapStateToProps = (state, ownProps = {}) => { + console.log(state); // state + console.log(ownProps); // undefined +}; +``` + +Functions with no mandatory parameters or two parameters **will receive** `ownProps`. + +```javascript +const mapStateToProps = (state, ownProps) => { + console.log(state); // state + console.log(ownProps); // ownProps +}; +``` + +```javascript +function mapStateToProps() { + console.log(arguments[0]); // state + console.log(arguments[1]); // ownProps +} +``` + +```javascript +const mapStateToProps = (...args) => { + console.log(args[0]); // state + console.log(args[1]); // ownProps +}; +``` + + + +##### Optimizing connect when options.pure is true + +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. Here are several examples: + +* 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. For example: `areStatesEqual: (next, prev) => prev.entities.todos === next.entities.todos`; this would effectively ignore state changes for everything but that slice of state. + +* You may wish to override `areStatesEqual` to always return false (`areStatesEqual: () => false`) if you have impure reducers that mutate your store state. (This would likely impact the other equality checks as well, depending on your `mapStateToProps` function.) + +* 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).) + +* 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. + +* You may wish to override `areMergedPropsEqual` to implement a `deepEqual` if your selectors produce complex props. ex: nested objects, new arrays, etc. (The deep equal check should be faster than just re-rendering.) + +#### Returns + +A higher-order React component class that passes state and action creators into your component derived from the supplied arguments. This is created by `connectAdvanced`, and details of this higher-order component are covered there. + + + +#### Examples + +##### Inject just `dispatch` and don't listen to store + +```js +export default connect()(TodoApp); +``` + +##### Inject all action creators (`addTodo`, `completeTodo`, ...) without subscribing to the store + +```js +import * as actionCreators from "./actionCreators"; + +export default connect(null, actionCreators)(TodoApp); +``` + +##### Inject `dispatch` and every field in the global state + +> Don’t do this! It kills any performance optimizations because `TodoApp` will rerender after every state change. +> It’s better to have more granular `connect()` on several components in your view hierarchy that each only +> listen to a relevant slice of the state. + +```js +export default connect(state => state)(TodoApp); +``` + +##### Inject `dispatch` and `todos` + +```js +function mapStateToProps(state) { + return { todos: state.todos }; +} + +export default connect(mapStateToProps)(TodoApp); +``` + +##### Inject `todos` and all action creators + +```js +import * as actionCreators from "./actionCreators"; + +function mapStateToProps(state) { + return { todos: state.todos }; +} + +export default connect(mapStateToProps, actionCreators)(TodoApp); +``` + +##### Inject `todos` and all action creators (`addTodo`, `completeTodo`, ...) as `actions` + +```js +import * as actionCreators from "./actionCreators"; +import { bindActionCreators } from "redux"; + +function mapStateToProps(state) { + return { todos: state.todos }; +} + +function mapDispatchToProps(dispatch) { + return { actions: bindActionCreators(actionCreators, dispatch) }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp); +``` + +##### Inject `todos` and a specific action creator (`addTodo`) + +```js +import { addTodo } from "./actionCreators"; +import { bindActionCreators } from "redux"; + +function mapStateToProps(state) { + return { todos: state.todos }; +} + +function mapDispatchToProps(dispatch) { + return bindActionCreators({ addTodo }, dispatch); +} + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp); +``` + +##### Inject `todos` and specific action creators (`addTodo` and `deleteTodo`) with shorthand syntax + +```js +import { addTodo, deleteTodo } from "./actionCreators"; + +function mapStateToProps(state) { + return { todos: state.todos }; +} + +const mapDispatchToProps = { + addTodo, + deleteTodo +}; + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp); +``` + +##### Inject `todos`, todoActionCreators as `todoActions`, and counterActionCreators as `counterActions` + +```js +import * as todoActionCreators from "./todoActionCreators"; +import * as counterActionCreators from "./counterActionCreators"; +import { bindActionCreators } from "redux"; + +function mapStateToProps(state) { + return { todos: state.todos }; +} + +function mapDispatchToProps(dispatch) { + return { + todoActions: bindActionCreators(todoActionCreators, dispatch), + counterActions: bindActionCreators(counterActionCreators, dispatch) + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp); +``` + +##### Inject `todos`, and todoActionCreators and counterActionCreators together as `actions` + +```js +import * as todoActionCreators from "./todoActionCreators"; +import * as counterActionCreators from "./counterActionCreators"; +import { bindActionCreators } from "redux"; + +function mapStateToProps(state) { + return { todos: state.todos }; +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators( + Object.assign({}, todoActionCreators, counterActionCreators), + dispatch + ) + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp); +``` + +##### Inject `todos`, and all todoActionCreators and counterActionCreators directly as props + +```js +import * as todoActionCreators from "./todoActionCreators"; +import * as counterActionCreators from "./counterActionCreators"; +import { bindActionCreators } from "redux"; + +function mapStateToProps(state) { + return { todos: state.todos }; +} + +function mapDispatchToProps(dispatch) { + return bindActionCreators( + Object.assign({}, todoActionCreators, counterActionCreators), + dispatch + ); +} + +export default connect(mapStateToProps, mapDispatchToProps)(TodoApp); +``` + +##### Inject `todos` of a specific user depending on props + +```js +import * as actionCreators from "./actionCreators"; + +function mapStateToProps(state, ownProps) { + return { todos: state.todos[ownProps.userId] }; +} + +export default connect(mapStateToProps)(TodoApp); +``` + +##### Inject `todos` of a specific user depending on props, and inject `props.userId` into the action + +```js +import * as actionCreators from "./actionCreators"; + +function mapStateToProps(state) { + return { todos: state.todos }; +} + +function mergeProps(stateProps, dispatchProps, ownProps) { + return Object.assign({}, ownProps, { + todos: stateProps.todos[ownProps.userId], + addTodo: text => dispatchProps.addTodo(ownProps.userId, text) + }); +} + +export default connect(mapStateToProps, actionCreators, mergeProps)(TodoApp); +``` + +##### Factory functions + +Factory functions can be used for performance optimizations + +```js +import { addTodo } from './actionCreators' + +function mapStateToPropsFactory(initialState, initialProps) { + const getSomeProperty= createSelector(...); + const anotherProperty = 200 + initialState[initialProps.another]; + return function(state){ + return { + anotherProperty, + someProperty: getSomeProperty(state), + todos: state.todos + } + } +} + +function mapDispatchToPropsFactory(initialState, initialProps) { + function goToSomeLink(){ + initialProps.history.push('some/link'); + } + return function(dispatch){ + return { + addTodo + } + } +} + + +export default connect(mapStateToPropsFactory, mapDispatchToPropsFactory)(TodoApp) +``` + + + +### `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. + + + +#### 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` + + * [`storeKey`] _(String)_: the key of props/context to get the store. You probably only need this if you are in the inadvisable position of having multiple stores. Default value: `'store'` + + * [`withRef`] _(Boolean)_: If true, stores a ref to the wrapped component instance and makes it available via `getWrappedInstance()` method. Default value: `false` + + * 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. + +##### Instance Methods + +###### `getWrappedInstance(): ReactComponent` + +Returns the wrapped component instance. Only available if you pass `{ withRef: true }` as part of the `options` argument. + +#### 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); +``` + + + +### `createProvider([storeKey])` + +Creates a new `` which will set the Redux Store on the passed key of the context. You probably only need this if you are in the inadvisable position of having multiple stores. You will also need to pass the same `storeKey` to the `options` argument of [`connect`](#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options) + + + +#### Arguments + +* [`storeKey`](*String*): The key of the context on which to set the store. Default value: `'store'` + +#### Examples + +Before creating multiple stores, please go through this FAQ: [Can or should I create multiple stores?](http://redux.js.org/docs/faq/StoreSetup.html#can-or-should-i-create-multiple-stores-can-i-import-my-store-directly-and-use-it-in-components-myself) + +```js +import { connect, createProvider } from "react-redux"; + +const STORE_KEY = "componentStore"; + +export const Provider = createProvider(STORE_KEY); + +function connectExtended( + mapStateToProps, + mapDispatchToProps, + mergeProps, + options = {} +) { + options.storeKey = STORE_KEY; + return connect(mapStateToProps, mapDispatchToProps, mergeProps, options); +} + +export { connectExtended as connect }; +``` + +Now you can import the above `Provider` and `connect` and use them. diff --git a/docusaurus/docs/api/Provider.md b/docusaurus/docs/api/Provider.md new file mode 100644 index 000000000..2d14a6dab --- /dev/null +++ b/docusaurus/docs/api/Provider.md @@ -0,0 +1,75 @@ +# `` + +## Overview + +The `` makes the Redux `store` available to any nested components that have been wrapped in the `connect()` function. + +Since any React component in a React-Redux app can be connected, most applications will render a `` at the top level, with the entire app’s component tree inside of it. + +Normally, you can’t use a connected component unless it is nested inside of a `` . + +Note: If you really need to, you can manually pass `store` as a prop to a connected component, but we only recommend to do this for stubbing `store` in unit tests, or in non-fully-React codebases. Normally, you should just use ``. + +### Props + +`store` (Redux Store) +The single Redux `store` in your application. + +`children` (ReactElement) +The root of your component hierarchy. + + +### Example Usage + +In the example below, the `` component is our root-level component. This means it’s at the very top of our component hierarchy. + +**Vanilla React Example** + +```js + import React from 'react'; + import ReactDOM from 'react-dom'; + import { Provider } from 'react-redux'; + + import { App } from './App'; + import createStore from './createReduxStore'; + + const store = createStore(); + + ReactDOM.render( + + + , + document.getElementById('root') + ) +``` + + +**Usage with React Router** + +```js + import React from 'react'; + import ReactDOM from 'react-dom'; + import { Provider } from 'react-redux'; + import { Router, Route } from 'react-router-dom'; + + import { App } from './App'; + import { Foo } from './Foo'; + import { Bar } from './Bar'; + import createStore from './createReduxStore'; + + const store = createStore(); + + ReactDOM.render( + + + + + + + + , + document.getElementById('root') + ) +``` + + diff --git a/docusaurus/docs/troubleshooting.md b/docusaurus/docs/troubleshooting.md new file mode 100644 index 000000000..8de80eba4 --- /dev/null +++ b/docusaurus/docs/troubleshooting.md @@ -0,0 +1,86 @@ +--- +id: troubleshooting +title: Troubleshooting +sidebar_label: Troubleshooting +--- + +Make sure to check out [Troubleshooting Redux](http://redux.js.org/docs/Troubleshooting.html) first. + +### I'm getting the following alert: Accessing PropTypes via the main React package is deprecated. Use the prop-types package from npm instead. + +This warning is shown when using react 15.5.\*. Basically, now it's just a warning, but in react16 the application might break. the PropTypes should now be imported from 'prop-types' package, and not from the react package. + +Update to the latest version of react-redux. + +### My views aren’t updating! + +See the link above. +In short, + +* Reducers should never mutate state, they must return new objects, or React Redux won’t see the updates. +* Make sure you either bind action creators with the `mapDispatchToProps` argument to `connect()` or with the `bindActionCreators()` method, or that you manually call `dispatch()`. Just calling your `MyActionCreators.addTodo()` function won’t work because it just _returns_ an action, but does not _dispatch_ it. + +### My views aren’t updating on route change with React Router 0.13 + +If you’re using React Router 0.13, you might [bump into this problem](https://github.com/reduxjs/react-redux/issues/43). The solution is simple: whenever you use `` or the `Handler` provided by `Router.run`, pass the router state to it. + +Root view: + +```js +Router.run(routes, Router.HistoryLocation, (Handler, routerState) => { + // note "routerState" here + ReactDOM.render( + + {/* note "routerState" here */} + + , + document.getElementById("root") + ); +}); +``` + +Nested view: + +```js +render() { + // Keep passing it down + return +} +``` + +Conveniently, this gives your components access to the router state! +You can also upgrade to React Router 1.0 which shouldn’t have this problem. (Let us know if it does!) + +### My views aren’t updating when something changes outside of Redux + +If your views depend on global state or [React “context”](http://facebook.github.io/react/docs/context.html), you might find that views decorated with `connect()` will fail to update. + +> This is because `connect()` implements [shouldComponentUpdate](https://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate) by default, assuming that your component will produce the same results given the same props and state. This is a similar concept to React’s [PureRenderMixin](https://facebook.github.io/react/docs/pure-render-mixin.html). + +The _best_ solution to this is to make sure that your components are pure and pass any external state to them via props. This will ensure that your views do not re-render unless they actually need to re-render and will greatly speed up your application. + +If that’s not practical for whatever reason (for example, if you’re using a library that depends heavily on React context), you may pass the `pure: false` option to `connect()`: + +``` +function mapStateToProps(state) { + return { todos: state.todos } +} + +export default connect(mapStateToProps, null, null, { + pure: false +})(TodoApp) +``` + +This will remove the assumption that `TodoApp` is pure and cause it to update whenever its parent component renders. Note that this will make your application less performant, so only do this if you have no other option. + +### Could not find "store" in either the context or props + +If you have context issues, + +1. [Make sure you don’t have a duplicate instance of React](https://medium.com/@dan_abramov/two-weird-tricks-that-fix-react-7cf9bbdef375) on the page. +2. Make sure you didn’t forget to wrap your root or some other ancestor component in [``](#provider-store). +3. Make sure you’re running the latest versions of React and React Redux. + +### Invariant Violation: addComponentAsRefTo(...): Only a ReactOwner can have refs. This usually means that you’re trying to add a ref to a component that doesn’t have an owner + +If you’re using React for web, this usually means you have a [duplicate React](https://medium.com/@dan_abramov/two-weird-tricks-that-fix-react-7cf9bbdef375). Follow the linked instructions to fix this. diff --git a/docusaurus/website/README.md b/docusaurus/website/README.md new file mode 100644 index 000000000..f3da77ff3 --- /dev/null +++ b/docusaurus/website/README.md @@ -0,0 +1,193 @@ +This website was created with [Docusaurus](https://docusaurus.io/). + +# What's In This Document + +* [Get Started in 5 Minutes](#get-started-in-5-minutes) +* [Directory Structure](#directory-structure) +* [Editing Content](#editing-content) +* [Adding Content](#adding-content) +* [Full Documentation](#full-documentation) + +# Get Started in 5 Minutes + +1. Make sure all the dependencies for the website are installed: + +```sh +# Install dependencies +$ yarn +``` +2. Run your dev server: + +```sh +# Start the site +$ yarn start +``` + +## Directory Structure + +Your project file structure should look something like this + +``` +my-docusaurus/ + docs/ + doc-1.md + doc-2.md + doc-3.md + website/ + blog/ + 2016-3-11-oldest-post.md + 2017-10-24-newest-post.md + core/ + node_modules/ + pages/ + static/ + css/ + img/ + package.json + sidebar.json + siteConfig.js +``` + +# Editing Content + +## Editing an existing docs page + +Edit docs by navigating to `docs/` and editing the corresponding document: + +`docs/doc-to-be-edited.md` + +```markdown +--- +id: page-needs-edit +title: This Doc Needs To Be Edited +--- + +Edit me... +``` + +For more information about docs, click [here](https://docusaurus.io/docs/en/navigation) + +## Editing an existing blog post + +Edit blog posts by navigating to `website/blog` and editing the corresponding post: + +`website/blog/post-to-be-edited.md` +```markdown +--- +id: post-needs-edit +title: This Blog Post Needs To Be Edited +--- + +Edit me... +``` + +For more information about blog posts, click [here](https://docusaurus.io/docs/en/adding-blog) + +# Adding Content + +## Adding a new docs page to an existing sidebar + +1. Create the doc as a new markdown file in `/docs`, example `docs/newly-created-doc.md`: + +```md +--- +id: newly-created-doc +title: This Doc Needs To Be Edited +--- + +My new content here.. +``` + +1. Refer to that doc's ID in an existing sidebar in `website/sidebar.json`: + +```javascript +// Add newly-created-doc to the Getting Started category of docs +{ + "docs": { + "Getting Started": [ + "quick-start", + "newly-created-doc" // new doc here + ], + ... + }, + ... +} +``` + +For more information about adding new docs, click [here](https://docusaurus.io/docs/en/navigation) + +## Adding a new blog post + +1. Make sure there is a header link to your blog in `website/siteConfig.js`: + +`website/siteConfig.js` +```javascript +headerLinks: [ + ... + { blog: true, label: 'Blog' }, + ... +] +``` + +2. Create the blog post with the format `YYYY-MM-DD-My-Blog-Post-Title.md` in `website/blog`: + +`website/blog/2018-05-21-New-Blog-Post.md` + +```markdown +--- +author: Frank Li +authorURL: https://twitter.com/foobarbaz +authorFBID: 503283835 +title: New Blog Post +--- + +Lorem Ipsum... +``` + +For more information about blog posts, click [here](https://docusaurus.io/docs/en/adding-blog) + +## Adding items to your site's top navigation bar + +1. Add links to docs, custom pages or external links by editing the headerLinks field of `website/siteConfig.js`: + +`website/siteConfig.js` +```javascript +{ + headerLinks: [ + ... + /* you can add docs */ + { doc: 'my-examples', label: 'Examples' }, + /* you can add custom pages */ + { page: 'help', label: 'Help' }, + /* you can add external links */ + { href: 'https://github.com/facebook/Docusaurus', label: 'GitHub' }, + ... + ], + ... +} +``` + +For more information about the navigation bar, click [here](https://docusaurus.io/docs/en/navigation) + +## Adding custom pages + +1. Docusaurus uses React components to build pages. The components are saved as .js files in `website/pages/en`: +1. If you want your page to show up in your navigation header, you will need to update `website/siteConfig.js` to add to the `headerLinks` element: + +`website/siteConfig.js` +```javascript +{ + headerLinks: [ + ... + { page: 'my-new-custom-page', label: 'My New Custom Page' }, + ... + ], + ... +} +``` + +For more information about custom pages, click [here](https://docusaurus.io/docs/en/custom-pages). + +# Full Documentation + +Full documentation can be found on the [website](https://docusaurus.io/). diff --git a/docusaurus/website/core/Footer.js b/docusaurus/website/core/Footer.js new file mode 100644 index 000000000..480f2a490 --- /dev/null +++ b/docusaurus/website/core/Footer.js @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +const React = require("react"); + +class Footer extends React.Component { + docUrl(doc, language) { + const baseUrl = this.props.config.baseUrl; + return `${baseUrl}docs/${language ? `${language}/` : ""}${doc}`; + } + + pageUrl(doc, language) { + const baseUrl = this.props.config.baseUrl; + return baseUrl + (language ? `${language}/` : "") + doc; + } + + render() { + return ( + + ); + } +} + +module.exports = Footer; diff --git a/docusaurus/website/package.json b/docusaurus/website/package.json new file mode 100644 index 000000000..2b956ae84 --- /dev/null +++ b/docusaurus/website/package.json @@ -0,0 +1,14 @@ +{ + "scripts": { + "examples": "docusaurus-examples", + "start": "docusaurus-start", + "build": "docusaurus-build", + "publish-gh-pages": "docusaurus-publish", + "write-translations": "docusaurus-write-translations", + "version": "docusaurus-version", + "rename-version": "docusaurus-rename-version" + }, + "devDependencies": { + "docusaurus": "^1.4.0" + } +} diff --git a/docusaurus/website/pages/en/index.js b/docusaurus/website/pages/en/index.js new file mode 100755 index 000000000..e8a3b04b9 --- /dev/null +++ b/docusaurus/website/pages/en/index.js @@ -0,0 +1,120 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +const React = require("react"); + +const CompLibrary = require("../../core/CompLibrary.js"); + +const MarkdownBlock = CompLibrary.MarkdownBlock; /* Used to read markdown */ + +const siteConfig = require(`${process.cwd()}/siteConfig.js`); + +function docUrl(doc, language) { + return `${siteConfig.baseUrl}docs/${language ? `${language}/` : ""}${doc}`; +} + +class Button extends React.Component { + render() { + return ( + + ); + } +} + +Button.defaultProps = { + target: "_self" +}; + +const SplashContainer = props => ( +
+
+
{props.children}
+
+
+); + +const Logo = props => ( +
+ Project Logo +
+); + +const ProjectTitle = () => ( +

+ {siteConfig.title} + + + Official React bindings for [Redux](https://github.com/reduxjs/redux) + +

+); + +const PromoSection = props => ( +
+
+
{props.children}
+
+
+); + +class HomeSplash extends React.Component { + render() { + const language = this.props.language || ""; + return ( + +
+ + + + + +
+
+ ); + } +} + +const Installation = () => ( +
+

Installation

+ + React Redux requires **React 0.14 or later.** + + + ``` npm install --save + react-redux ``` + +
+); + +class Index extends React.Component { + render() { + const language = this.props.language || ""; + + return ( +
+ +
+ +
+
+ ); + } +} + +module.exports = Index; diff --git a/docusaurus/website/sidebars.json b/docusaurus/website/sidebars.json new file mode 100644 index 000000000..bee6b9ac6 --- /dev/null +++ b/docusaurus/website/sidebars.json @@ -0,0 +1,5 @@ +{ + "docs": { + "Docs": ["getting-started", "api", "troubleshooting"] + } +} diff --git a/docusaurus/website/siteConfig.js b/docusaurus/website/siteConfig.js new file mode 100644 index 000000000..6151a995c --- /dev/null +++ b/docusaurus/website/siteConfig.js @@ -0,0 +1,84 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// See https://docusaurus.io/docs/site-config for all the possible +// site configuration options. + +const siteConfig = { + title: "React Redux", // Title for your website. + tagline: "React Redux Documentation", + url: "https://your-docusaurus-test-site.com", // Your website URL + baseUrl: "/", // Base URL for your project */ + // For github.io type URLs, you would set the url and baseUrl like: + // url: 'https://facebook.github.io', + // baseUrl: '/test-site/', + + // Used for publishing and more + projectName: "react-redux", + organizationName: "facebook", + // For top-level user or org sites, the organization is still the same. + // e.g., for the https://JoelMarcey.github.io site, it would be set like... + // organizationName: 'JoelMarcey' + + // For no header links in the top nav bar -> headerLinks: [], + headerLinks: [ + { doc: "getting-started", label: "Getting started" }, + { doc: "api", label: "Api" }, + { doc: "troubleshooting", label: "Troubleshooting" } + ], + + /* path to images for header/footer */ + // headerIcon: "img/redux.svg", + // footerIcon: "img/redux.svg", + favicon: "img/favicon/favicon.ico", + + /* Colors for website */ + colors: { + primaryColor: "#20232a", + secondaryColor: "#61dafb" + }, + + /* Custom fonts for website */ + /* + fonts: { + myFont: [ + "Times New Roman", + "Serif" + ], + myOtherFont: [ + "-apple-system", + "system-ui" + ] + }, + */ + + // This copyright info is used in /core/Footer.js and blog RSS/Atom feeds. + copyright: `Copyright © ${new Date().getFullYear()} Your Name or Your Company Name`, + + highlight: { + // Highlight.js theme to use for syntax highlighting in code blocks. + theme: "default" + }, + + // Add custom scripts here that would be placed in