Add base template#1
Conversation
|
First observation based on the description: I'd prefer to have the folder named Also, I'd like to consider moving https://github.com/reduxjs/rtk-github-issues-example https://redux.js.org/style-guide/style-guide#structure-files-as-feature-folders-or-ducks |
|
@markerikson I think moving |
This comment has been minimized.
This comment has been minimized.
|
@nickmccurdy That's probably a good idea |
|
@BenLorantfy I've created a PR (#2). If you'd like to add me to your fork, I can help you merge the default template into it. |
|
No worries, I can handle rebasing it after #2 get's merged 🙂 |
|
I’m working on a code review, I’m not sure if rebasing preserves that |
|
ah ok I can merge instead then |
I'd like to link to Redux, Redux Toolkit, and React Redux in that order. Note that Redux Toolkit doesn't provide React bindings, and the docs don't seem to provide an introduction to Redux for new users. |
nickserv
left a comment
There was a problem hiding this comment.
Thanks for your help! Here are my thoughts so far.
| "@testing-library/jest-dom": "^4.2.4", | ||
| "@testing-library/user-event": "^7.1.2", | ||
| "react-redux": "^7.1.3", | ||
| "@reduxjs/toolkit": "^1.1.0" |
There was a problem hiding this comment.
@reduxjs/toolkit should be first to keep consistent order with npm install, so installing new packages doesn't create a noisier diff.
| @@ -0,0 +1,68 @@ | |||
| This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). | |||
There was a problem hiding this comment.
Maybe we should link to the Redux and/or Toolkit docs at the top. Should still link to the create-react-app docs and keep the rest of the readme though, as it's still relevant.
| .App-counter { | ||
| display: flex; | ||
| align-items: center; | ||
| /* margin-top: 14px; */ |
There was a problem hiding this comment.
We should either uncomment or remove this.
|
|
||
| const { actions } = slice; | ||
|
|
||
| export { actions, selectors, slice }; |
There was a problem hiding this comment.
Personally I find separate export lines easier to read.
There was a problem hiding this comment.
I would prefer simplicity and convention in a template.
There was a problem hiding this comment.
Done. Should I be exporting an object of selectors or individually exporting each selector? Same for actions?
| "name": "cra-template-redux", | ||
| "version": "1.0.0", | ||
| "scripts": { | ||
| "prettify": "prettier './template/src/**/*.js' --write", |
There was a problem hiding this comment.
Maybe we should use CRA's Prettier config so there's less noise if someone switches from the default template.
There was a problem hiding this comment.
They don't have a config file but I added the same flags they use here: https://github.com/facebook/create-react-app/blob/master/package.json#L19
| } | ||
| }); | ||
|
|
||
| export default store; |
There was a problem hiding this comment.
We could have export default configureStore(...).
| ); | ||
| const linkElement = getByText(/learn redux/i); | ||
| expect(linkElement).toBeInTheDocument(); | ||
| }); |
There was a problem hiding this comment.
This could be a good opportunity to show an example of testing a simple Redux app, since it's more interactive than the default template. If we're just sticking with a basic smoke test this is fine with me.
There was a problem hiding this comment.
@markerikson any thoughts on this? I can do a more in-depth test if we want.
There was a problem hiding this comment.
Something like so? https://testing-library.com/docs/example-react-redux
There was a problem hiding this comment.
I have a suggestion:
<span data-testid="count-value" className="App-counter-value">
{count}
</span>const setup = () =>
render(
<Provider store={store}>
<App />
</Provider>
);
test('renders learn redux toolkit link', () => {
const { getByText } = setup();
const linkElement = getByText(/redux toolkit/i);
expect(linkElement).toBeInTheDocument();
});
test('can increment value', () => {
const { getByTestId, getByText } = setup();
fireEvent.click(getByText('+'));
expect(getByTestId('count-value')).toHaveTextContent('1');
});
test('can decrement value', () => {
const { getByTestId, getByText } = setup();
fireEvent.click(getByText('-'));
expect(getByTestId('count-value')).toHaveTextContent('0');
});There was a problem hiding this comment.
I also believe it's worth to add tests for the reducer as well:
// src/features/counter.test.js
import counter, { actions } from './counter';
test('can increment value', () => {
expect(
counter(
{ value: 1 },
{
type: actions.increment.type,
}
).value
).toEqual(2);
});
test('can decrement value', () => {
expect(
counter(
{ value: 2 },
{
type: actions.decrement.type,
}
).value
).toEqual(1);
});There was a problem hiding this comment.
I can add something like that if we decide we want to add more in-depth testing.
|
could we add a prepare function somewhere? |
|
Now that the default template (#2) is merged, we can merge master back into this branch. |
Should I also move the counter UI to the counter feature folder? (and turn counter.js into a folder?) |
| </Provider> | ||
| ); | ||
|
|
||
| expect(getByText(/learn/i)).toBeInTheDocument(); |
There was a problem hiding this comment.
Maybe search for: /react redux/i instead of just /learn/i?
expect(getByText(/react redux/i)).toBeInTheDocument();|
@markerikson @nickmccurdy FYI, this is ready for another review 🙂 |
| "template.json" | ||
| ] | ||
| ], | ||
| "devDependencies": { |
There was a problem hiding this comment.
Where in the template process are these devDeps actually used? Why isn't most of this already handled as part of CRA / react-scripts itself?
There was a problem hiding this comment.
These dependencies don't end up in the project created by cra. These are just used by us to lint and test the code during development.
| align-items: center; | ||
| } | ||
|
|
||
| .App-counter-value { |
There was a problem hiding this comment.
I feel like this UI-specific CSS should be moved into a CSS modules file.
| <div className="App"> | ||
| <header className="App-header"> | ||
| <img src={logo} className="App-logo" alt="logo" /> | ||
| <p className="App-counter"> |
There was a problem hiding this comment.
Let's move all the counter UI into a <Counter /> component inside of features/counter.
| @@ -0,0 +1,25 @@ | |||
| import { createSlice } from '@reduxjs/toolkit'; | |||
There was a problem hiding this comment.
I'd like this file to be moved to features/counter/counterSlice.js.
|
|
||
| const selectCount = state => state.counter.value; | ||
|
|
||
| export const selectors = { |
There was a problem hiding this comment.
I don't think exporting the selector inside of an object helps here. Just do export const selectCount =.
For that matter, does the selector really buy us anything useful in terms of the example? It at least shows the idea of a selector, but it also doesn't show use of Reselect.
There was a problem hiding this comment.
I always like using selectors even for small things, since it hides the data structure from the consumers and therefore is easier to change. IMO the data structure of the state should be an implementation detail of the slice.
Up to you though.
| selectCount, | ||
| }; | ||
|
|
||
| export const { actions } = slice; |
There was a problem hiding this comment.
Export the action creators individually here:
| export const { actions } = slice; | |
| export const { increment, decrement} = slice.actions; |
| @@ -0,0 +1,8 @@ | |||
| import { configureStore } from '@reduxjs/toolkit'; | |||
| import * as slices from './features'; | |||
There was a problem hiding this comment.
I don't like the import * here. I'd rather explicitly do import counterReducer from "features/counter/counterSlice".
Similarly, I'd rather not bother with trying to reuse the slice.name field. Just say counter: counterReducer.
|
@markerikson @nickmccurdy Sorry for the delay; this is ready for another review now. |
| @@ -0,0 +1,31 @@ | |||
| .container { | |||
There was a problem hiding this comment.
In terms of naming convention, I've always preferred to make my CSS module files exactly match the name of the corresponding component files. In this case, that'd be capitalizing it to Counter.module.css.
| }, | ||
| reducers: { | ||
| increment: state => { | ||
| state.value += 1; |
There was a problem hiding this comment.
Would it be worth adding an explanatory comment here saying that "Redux Toolkit allows us to 'mutate' the state"?
| increment: state => { | ||
| state.value += 1; | ||
| }, | ||
| decrement: state => { |
There was a problem hiding this comment.
I'd like to see one other case handled here that actually shows using the action parameter as well. Maybe have an incrementByAmount case, and allow the user to enter a number in the UI?
|
@markerikson This is ready for another review 🙂 |
|
@markerikson Just pinging |
| <p> | ||
| Edit <code>src/App.js</code> and save to reload. | ||
| </p> | ||
| <a |
There was a problem hiding this comment.
Can we leave the "Learn React" link in here? That's over half of what the final app will be anyway :)
| @@ -0,0 +1,42 @@ | |||
| import React, { useState } from 'react'; | |||
There was a problem hiding this comment.
Oh, one other naming scheme thing.
I'd like to change this to Counter.js.
I've never been a fan of the "using index.js for all the components based on folders" thing.
There was a problem hiding this comment.
sure. Should the folder name be counter or Counter ?
There was a problem hiding this comment.
features/counter/Counter.js, please
|
Okay, I think I'm down to two nitpicks at this point. |
|
Awright, this is probably good enough to go with for now. Let's get this in! Uh... what are the next steps? I assume we need to re-publish the package. I have access to the |
|
Sounds good to me 👍 |
|
Awright, I'll try publishing it this evening. Would we want to call this 1.0.0? |
|
I'd say so |
|
Let me know if you need help with docs or any other release stuff |
|
I published 0.0.1, and did find one bug: the CSS module import was now mismatched. Fixed that, published 0.0.2, created another CRA project with it, and that worked. Soooo... I've just published 1.0.0 ! https://github.com/reduxjs/cra-template-redux/releases/tag/v1.0.0 |
|
The next step would be to tackle https://github.com/reduxjs/cra-template-redux-typescript . We should be able to piece it together by starting from the CRA-TS base template, copying over the code contents from this template, and TS-ifying it. @BenLorantfy , you want to tackle that one too? |
|
Sure I can take a shot at it |
|
Just read through the template again and I think it's a solid overview of basic CRA and Redux Toolkit functionality, nice work! |
Creates a base template using
@reduxjs/toolkit.Started with cra default template and made some changes:
@reduxjs/toolkit, andreact-reduxas dependenciesstore.jsthat creates the store with the counter sliceindex.jsto wrapAppwithProviderA few open questions I have:
redux.js.orgorredux-toolkit.js.org?Screenshot of generated app:
