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

Docs: Rewrite tutorial to show hooks as the primary API #1574

Open
markerikson opened this issue Apr 28, 2020 · 33 comments
Open

Docs: Rewrite tutorial to show hooks as the primary API #1574

markerikson opened this issue Apr 28, 2020 · 33 comments
Labels

Comments

@markerikson
Copy link
Contributor

We're now at a point where I'm comfortable teaching our hooks API first (which I'm also doing right now as I work on the new "Quick Start" Redux core tutorial page).

Given that, it would be nice to convert the React-Redux tutorial over. Would still be helpful to have the connect intro somehow as well, albeit secondary.

@jerrybuks
Copy link

@markerikson is there any way I can help out with this?

@markerikson
Copy link
Contributor Author

Sure! No one's volunteered to tackle it yet, so it's up for grabs if you'd like to work on it.

For reference, here's the new "Redux Essentials" core docs tutorial where I covered use of the hooks as the default:

https://redux.js.org/tutorials/essentials/part-1-overview-concepts

I'd suggest looking through that and the React-Redux tutorial, coming up with a suggested plan / outline for a rework, and then post that here and we can discuss it.

@jerrybuks
Copy link

Okay, will jump on this and get back to you

@markerikson
Copy link
Contributor Author

Related to this, we need more details on what useDispatch even is and how to use it:

https://www.reddit.com/r/reactjs/comments/cc9ehv/need_help_with_new_redux_hooks/etmedoh/

@markerikson
Copy link
Contributor Author

It occurs to me that a good approach here might just be to copy-paste/port the "UI and React" page from the "Redux Fundamentals" tutorial I wrote for the core docs:

https://redux.js.org/tutorials/fundamentals/part-5-ui-react

@markerikson
Copy link
Contributor Author

A couple people have indicated interest in doing this, but no one has actually done so yet. Still interested in having someone tackle this!

@ligabloo
Copy link

I'm interested in doing that :)

@wjohnso-insight
Copy link

I'm interested in doing that :)

I'd be happy to work with you on that as well. I've worked through the essentials and fundamentals tutorials very recently so the conventions and style are still pretty fresh.

@markerikson
Copy link
Contributor Author

@ligabloo , @wjohnso-insight : Cool :)

Per my tweets and my comment above, I think that the best (and hopefully easiest) approach is to start by copying the content from that "Redux Fundamentals: UI and React" page.

We'd need to make updates to the content to:

  • Supply introductory context (what the todo app example is, existing app structure)
  • Replace links to other Redux core docs pages
  • Add some additional bits of info that are listed later in the "Fundamentals" tutorial, like dispatching using action creators, and using memoized selectors

But I do think that reusing that page gives us 90% of the content we need without having to rewrite it from scratch.

As much as I love the work that @wgao19 did on the existing connect tutorial, I think it's probably time to retire it. Or, perhaps we add a new "Tutorials" category, move both tutorials under that in the sidebar, but link the hooks tutorial as "Tutorial" in the navbar.

One other issue: right now, the React-Redux docs have this annoying "versioned docs" setup, which makes working on docs content a lot more complicated. Per #1693 , I actually want to drop that versioning setup.

I may try to tackle that myself tomorrow to help make it simpler to work on this.

@wjohnso-insight
Copy link

Sounds like a plan. I like the idea of reusing sections from the existing docs.

@markerikson Would you recommend reading up on Docusarus versioning just to get a feel for the terrain and for some context or is that overkill?

@markerikson
Copy link
Contributor Author

markerikson commented Mar 20, 2021

It's probably overkill for now. Really, there's a good chance that I may have it turned off completely by this time tomorrow :)

The short version is that the /docs folder actually becomes the "Next" version on the docs site: https://react-redux.js.org/next/introduction/quick-start

Meanwhile, the "Current (7.2)" version is actually located under /website/versioned_docs/7.2/, and there's also other versioned folders as well. So, if you edit a file under /docs, it won't show up in one of the default visible pages like https://react-redux.js.org/api/hooks - only if you specifically select the "Next" version from the dropdown. This has repeatedly resulted in people submitting docs PRs that don't actually show up on the site by default, and we have to keep saying "please also edit the duplicate files in the versioned folders!"

I'd say just create a new /docs/tutorials/ folder and create a hooks.md file in there or something, work on the content, and we'll deal with the versioning bit later.

@wjohnso-insight
Copy link

Gotcha!

@ricokahler
Copy link
Contributor

ricokahler commented Mar 20, 2021

We're now at a point where I'm comfortable teaching our hooks API first (which I'm also doing right now as I work on the new "Quick Start" Redux core tutorial page).

I'm really glad we're at this point! I think it's the right direction, especially since reactjs.org itself is undergoing the same transition to hooks-first docs.

I've been using hooks and the react-redux hooks since they've come out and I have a few opinionated takes I wanted to share. If you agree with any of these, feel free to take inspiration in the docs (otherwise, feel free to ignore 😅)

Click to reveal wall of text

Why hooks first?

Hooks are the React team's solution to many problems in React. They represent the continued future of React and as stated before, they're also transitioning the current docs to be hooks-first.

I think it's important to state why hooks should be the preferred option over connect. Here are my reasons (no particular order):

  • Much easier to use with TypeScript
  • Easier to compose with other pieces of global state (e.g. react-router). Discourages copying state into Redux
  • Easier to understand due to less indirection
  • Works well with the default React hooks and replaces the need for some memorization libraries (not a sliver bullet though)

Easier to use with TypeScript

This one is just easy to get out of the way. React hooks were built with static typing in mind. Properly adding types to a higher-order component is complex and confusing. Hooks return the values they inject inline, types intact. This holds true for react-redux.

Easier to compose with other pieces of global state

React hooks were built for composition. If you want to join two or more pieces of state, you can do so in the component inline now.

import { useSelector } from 'react-redux';
import { useParams } from 'react-router';

function Component() {
  // global state from react-router
  const { id } = useParams();

  // global state from redux combined with state from react-router
  const item = useSelector(state => state.entities[id]);

  // local state using the redux state as an initial value
  const [active, setActive] = useState(item.active);

  // ...
}

And custom hooks can elevate these into reusable pieces:

import { useSelector } from 'react-redux';
import { useParams } from 'react-router';

function useItem() {
  const { id } = useParams();
  const item = useSelector(state => state.entities[id]);
  
  return item;
}

function Component() {
  const item = useItem();
}

This contrasts heavily with some previous best practices back in the day. For example, the purpose of the proejcts react-router-redux and connected-react-router were to copy the state of react-router into redux state just so it could be used in mapStateToProps. Given the complexity of higher-order components, this was a very valid pattern but now seems like the wrong place given the ability to compose inline a component or in custom hooks.

Easier to understand due to less indirection

useSelector/useDispatch are APIs with a lighter footprint. You use them inline, directly in the component.

If you want to grab a particular item from state, you can directly return it from useSelector (with the types intact). If you want to dispatch an action, it's perfectly fine to call dispatch inline

import { selectItem } from '../actions';

function Component() {
  const { id } = useParams();
  const item = useSelector(state => state.items[id]);

  if (!item) {
    return <>Loading…</>;
  }

  return (
    <>
      <h1>{item.title}</h1>
      <button
        onClick={() => {
          dispatch(selectItem(id));
        }}
      >select this item</button>
    </>
  );
}

Compare this with the connect version:

import React from 'react';
import { connect } from 'react-redux';
import { withRouter } from 'react-router';
import { selectItem } from '../actions';

const mapStateToProps = (state, ownProps) => {
  const { location } = ownProps;
  const { id } = location.match;
  const item = state.items[id];

  return { item }
};

// you could return dispatch directly however, that's not the meta for redux
// with useDispatch, you don't have a choice
const mapDispatchToProps = { selectItem };

class Component extends React.Component {
  render() {
    const { item, selectItem, location } = this.props;
    const { id } = location.params;

    if (!item) {
      return <>Loading…</>;
    }

    return (
      <>
        <h1>{item.title}</h1>
        <button
          onClick={() => selectItem(id)}
        >select this item</button>
      </>
    );
  }
}

// it's very hard to add types to this
export default withRouter(connect(
  mapStateToProps,
  mapDispatchToProps
)(Component));

Works well with the default React hooks

In particular, I've found it useful to intentionally not calculate values in useSelector and instead rely on built-in optimizations like useMemo and React.memo.

// note: this is an intentionally complex/contrived example
import { memo, useMemo } from 'react';
import { useSelector } from 'react-redux';

function Wrapper() {
  const { id } = useParams();
  const item = useSelector(state => state.items[id]);

  const { sublist } = item;
  const expensiveCalculation = useMemo(() => {
    return sublist.reduce((acc, next) => { /* ... */ }, {});
  }, [sublist]);

  return <ExpensiveRenderingComponent expensiveCalculation={expensiveCalculation} />;
}

const ExpensiveRenderingComponent = memo(({ expensiveCalculation }) => {
  // ...
});

And useSelector/useDispatch also work well with useEffect

function Component() {
  const dispatch = useDispatch();
  const count = useSelector(state => state.screen.count);
  const greaterThanFive = count > 5;

  useEffect(() => {
    if (greaterThanFive) {
      dispatch(showMessage());
    }
  }, [greaterThanFive, dispatch]);

  return // ...
}

In general, I like to be as React idiomatic as possible and hooks-first is the way 😎

Anyway, that's all I got!

@ligabloo
Copy link

@markerikson I also like the idea of reusing the existing redux fundamentals docs, will make it easier to get started for sure.

@wjohnso-insight I appreciate it! How would we go about collaborating in this case? We checkout a new branch from master, push it and then work on it simultaneously? Also, how could we split the work?

@ricokahler those seem like good points to me!

@markerikson
Copy link
Contributor Author

@ligabloo Yeah, if you're going to collaborate on this, I'd suggest that one of you should create a fork of this repo, give the other person collaborator permissions on that fork, and both push changes to that branch as appropriate. Once you've got something ready, you can PR from that fork back over to here.

I'm playing around with removing the versioning right now, so I think you can safely assume that the new file should live in /docs/tutorials/hooks.md.

@wjohnso-insight
Copy link

@ligabloo Looking forward to working with you! If you want to make the fork and add me as a collaborator that works for me.

Tomorrow I'll take a look at the old code base and the reference from the UI & React tuts and star putting some cards together and we can divvy up from there. Sound good?

@ligabloo
Copy link

@wjohnso-insight sounds awesome! I'll also start tomorrow since it's already kinda late here 😅 I'm setting up the fork and adding you as a collaborator so we can be ready to go.

@markerikson
Copy link
Contributor Author

Great, appreciate both of you jumping in on this! :) Please feel free to ping me over in the Reactiflux Discord #redux channel if you've got any questions I can help with.

@markerikson
Copy link
Contributor Author

markerikson commented Mar 20, 2021

aaaand done! just nuked the versioning setup, so you'll probably want to go ahead and do a fresh pull from master over into your fork before you get started. I also moved the legacy connect tutorial into /docs/tutorials/connect.md.

@ligabloo
Copy link

@wjohnso-insight I copy-pasted the tutorial from redux essentials into tutorials/hooks.md and made minimal adjustments to the front matter and sidebar config to make docusaurus properly build the site and render the page. For dev purposes I just replaced the sidebar link with the new hooks document, but I'm aware we'll need to restructure that section to show both links in the future.

I suppose we could start by nuking the "Introduction" and "Integrating Redux with a UI" sections and replace them with more specific introductory content about the tutorial and redux-react themselves, right?

@markerikson about the existing links - do we want to keep them redirecting to redux official docs or do we want to replace them with something else? I see some of them link to other steps of the essentials tutorials, would linking directly to them be confusing out of the original context?

@markerikson
Copy link
Contributor Author

markerikson commented Mar 20, 2021

Yeah, those are the sorts of "content edits" I'm describing. I'd like this to be a standalone document in the React-Redux repo, instead of blatantly being "the middle of another tutorial we ripped out and copied".

However, it would be good to point to the core docs "Fundamentals" tutorial in a "Prerequisites" info box at the top of the page, similar to how the first pages of the "Fundamentals" and "Essentials" tutorials start by saying "you should know HTML, JS, and React":

https://redux.js.org/tutorials/essentials/part-1-overview-concepts

I can see arguments both ways on whether to keep the "Integrating Redux with a UI" section. On the one hand, it's not strictly necessary to read that to know how to use the hooks. On the other hand, seeing that example should make it more clear what the hooks are doing and how they work, conceptually.

Eh... let's pull that section out of here for now to keep this focused on "how to use it". I've been meaning to add a "how it works" page to the React-Redux docs for years now :) we can drop that material in there.

@wjohnso-insight
Copy link

@ligabloo Have you made me a contributor to your fork yet?

@ligabloo
Copy link

@ligabloo Have you made me a contributor to your fork yet?

Yep - I sent you an invitation, did you get anything in your email / notifications?

@wjohnso-insight
Copy link

Ope! Got sent to spam. I'm in now. Also, are you on Discord? Hit me up. @chef_will

@ligabloo
Copy link

@wjohnso-insight tried finding you there, but I think I need the four-digit tag as well 😛

@wjohnso-insight
Copy link

My b! chef_will#5730

@wjohnso-insight
Copy link

Just a quick update on behalf of @ligabloo and myself. Our refactor to Hooks first documentation is proceeding well.

@ligabloo has re-written the todo list application using hooks and RTX, here .

I drafted the outline for the new tutorial copy here and have started pushing commits to our fork based on this outline. I should have the first draft together in the next day or so.

Once we have a working draft we will perform some quick-and-dirty QA testing by asking Reactiflux members to complete the tutorial and soliciting them for notes/comment. Once we have amended a final draft and incorporated user comment we will open a PR with our fork.

@markerikson
Copy link
Contributor Author

Nice!

My experience with CodeSandboxes for examples is that they work best when the code is actually in a Github repo, and the sandbox is pointed to a specific branch or tag. You can see that in the existing tutorials.

My suggestion would be that we should create a react-hooks-tutorial branch in the existing Fundamentals repo based off of the initial master commit, and merge the RTK-rewritten all-React starting point into that branch. Then we can have a couple additional commits on that branch with the rest of the code shown in the tutorial.

@markerikson
Copy link
Contributor Author

@wjohnso-insight @ligabloo hey, wanted to follow up on this - are you still working on the tutorial migration?

@ligabloo
Copy link

ligabloo commented May 1, 2021

@markerikson hey, Mark! So, we've had a bit of a pause since last month - personally, I've been kind of busy with work and that messed up my schedules and such, but yeah, I still intend to continue working on this.

This is the progress we've made so far: https://github.com/ligabloo/react-redux/blob/master/docs/tutorials/hooks.md
Also, @wjohnso-insight has created issues for the different sections that are still missing, if you want to check that: https://github.com/ligabloo/react-redux/issues.

I'd appreciate if you could give us feedback on what we've written (well, mostly @wjohnso-insight, I've helped with the code samples and some minor suggestions) so far and if it matches what you're expecting out of the tutorial 😃

@markerikson
Copy link
Contributor Author

markerikson commented May 1, 2021

@ligabloo gotcha, thanks for the update!

Glancing at that page, I'd actually suggest cutting down on the amount of explanation of basic store setup. Ultimately the goal here is to teach setting up the React-Redux portion and using it, vs teaching Redux itself.

I do note that we don't really have a good spot that explains "how to set up configureStore from scratch", exactly. The "Essentials" tutorial comes with that store setup already in place in the example app. The "Fundamentals" tutorial does show use of configureStore, but only by migrating existing setup logic.

Perhaps we could add one other "Quick Start" tutorial to the Redux core docs. We've already got one in the RTK docs at https://redux-toolkit.js.org/tutorials/quick-start , and it would seem reasonable to put that in the Redux docs.

So, I think my main suggestion here would be point to "Understanding of Redux core concepts" as a prerequisite, and focus this section more on the React-Redux APIs.

@ligabloo
Copy link

Hello @markerikson, I've been thinking on this from time to time, and it seems like I can't never really find time to get back to it. 😞 I'm sorry for taking so long to tell, but I decided it would be best to do it know rather then hoarding this task even longer while some other person might be interested in going through with it. I'll try to talk with some of my work colleagues to see if anyone is interested in contributing (and able to do so). Still, I hope to be able to help with something else in the future, since Redux has been a fundamental tool that I've used daily for years.

@markerikson
Copy link
Contributor Author

@ligabloo no worries, I appreciate the effort, and I totally understand being too busy!

Could you do me a favor? Go ahead and open up a PR with whatever content you have so far, and create issues here in the repo matching what you were planning to do. That way someone else can pick up with the effort.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants