React-cra – Amin is available at github.com/yayxs/react…

Contains a series of tutorial documentation.

preface

background

From the current actual background, about the project in the background management system is our usual so-called admin project. Have to mention is flower underpants idol and Tang Jinzhou idol. And so on. Only from the react stack, we must think of the ANTD series, including

  • UI framework antd
  • The data flow dva
  • Practice framework ANTD-Pro
  • Integration solution UmiJS

Recently studied their source code, there is a specification in. Worthy of further discussion and study. But the rest of the article is all JS. Why emphasize this point. With current trends, React is pretty much all about TypeScrit: Learn the ANTD series and learn the TS version as well.

contrastVue

While we’re focusing on React, we have to mention vue’s admin solutions. There are plenty of mature and elegant ones in the community, including the ones mentioned above

  • PanJiaChen/vue-element-admin
  • vueComponent/ant-design-vue

However, from the perspective of Create Raect app, there are other solutions to modify the configuration of Webpack by popping up the webpack configuration (note that it is not recommended to pop up directly), please search by yourself. The more schemes adopted are the more mature set of UMiJS. On how to build a simple background management scheme from 0 foundation, we will talk about next.

The CRA mentioned below stands for Create React app

aboutMockdata

Mock requests for data have long been a common operation for front-end projects, and it’s a good idea to run Mock scripts before running this project. For our next proxy request, it looks something like this. Create a new MockServer.js at the root of your project, the core code

app.use("/api/login/account".function (req, res) {
  console.log(req.body);
  const { password, userName, type } = req.body;
  if (password === "admin" && userName === "admin") {
    res.send({
      status: "ok",
      type,
      currentAuthority: "admin"});return;
  }

  if (password === "user" && userName === "user") {
    res.send({
      status: "ok",
      type,
      currentAuthority: "user"});return;
  }

  if (type === "mobile") {
    res.send({
      status: "ok",
      type,
      currentAuthority: "admin"});return;
  }

  res.send({
    status: "error".// type,
    currentAuthority: "guest"}); });Copy the code

The above part is also the mock part of the user in ANTD-Pro of CV. Our API runs on port 8080, and by default our project starts at port 3000

const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = function (app) {
  app.use(
    "/api",
    createProxyMiddleware({
      target: "http://localhost:8080".changeOrigin: true,})); };Copy the code

Access the Api start proxy to 8080. In chapter 1, we did not introduce RKT(Redux Toolkit) so we simply tested, at login page time, we made the request through AXIos

axios
  .post(`/api/login/account`, {
    userName: "admin".password: "admin".type: "hah",
  })
  .then((res) = > {
    console.log(res);

    comLocalStorage.set("token".123 ` `);
    history.replace(from);
  })
  .catch((err) = > {
    console.log(err);
  });
Copy the code

The login succeeds.

Public methods

Because local storage is very important, it is also a way to store data in the project, so it is simply encapsulated. Of course, it can be optimized for custom Hook in the future. Here I will first encapsulate it as a static method of the class

See the complete code SRC/utils/comLocalStorage js

/* * @author: yayxs * @date: * @description: Encapsulates local storage */
const localStore = window.localStorage;
class ComLocalStorage {
  // Set the data to a stringif value is obj by calling json.stringify
  static set(key, value) {
    if(! localStore) {return;
    }
    let v = value;
    try {
      if (typeof value === "object") {
        v = JSON.stringify(v);
      }
      localStore.setItem(key, v);
    } catch (error) {
      // error}}// Read directly
  static get(key) {
    if(! localStore) {return;
    }
    return localStore.getItem(key);
  }
  // Read to Obj
  static get2Json(key) {
    if(! localStore) {return;
    }
    const data = localStore.getItem(key);
    if (data) {
      try {
        return JSON.parse(data);
      } catch (error) {
        // todo error}}return null;
  }
  // Remove it directly
  static remove(key) {
    if(! localStore) {return;
    }
    try {
      localStore.removeItem(key);
    } catch (error) {
      // todo error}}}export default ComLocalStorage;
Copy the code

Routing authentication

The best way to learn about routing configuration and APIS is to consult the official documentation, and of course you can also see github.com/yayxs/react… Will be updated all the time, so far just started. So don’t look at it for a while

But the first thing we need to do to get dynamic parameters is to use useParams

Just like when we configure the routing table,

 {
    path: "/admin/lists/edit/:id?".component: Edit,
    isShow: false
  },
Copy the code

To obtain this parameter, use useParams. In this way, props.mate.params. id cannot be obtained. Okay, so let’s focus on the analysis, the route section jumps directly to the login page without logging in

Hit the index. Js

We know react was in a hurry to find index.js. Render directly to the page

ReactDOM.render(<RootPage />.document.getElementById("root"));
Copy the code

Hit RootPage

A couple of things to start with

  • The React route exit is used<Router>The component is wrapped, let’s call it that
  • When accessing/Direct redirection
  • But when all the paths/adminWhat we’re really going to start with is<App />Component, this is alsobasicLayoutView render exit location
  • For generic routes such as login or 404, where the page is bare, without the outer box (green), just render it

<Router>
  <Switch>{/* When access is located to dashboard*/}<Route
      path="/"
      exact
      render={()= > <Redirect to="/admin/dashboard" push />}
    ></Route>{/* Access /admin render APP is required to login to access */}<Route path="/admin" render={(props)= > <App {. props} / >} ></Route>
    {routesConfig["other"].map((item) => (
      <Route
        key={item.path}
        path={item.path}
        component={item.component}
      ></Route>)} {/* Access is redirected directly to admin */} {/*<Redirect to="/admin" from="/" />*/ * 404 page */}<Redirect to="/ 404" />
  </Switch>
</Router>
Copy the code

hit<App />

Render the view directly if logged in, redirect to the login page otherwise

<DocumentTitle title={title}>
  {isLogined() ? (
    <>
      <BaseLayout>
        <RenderRoutes />
      </BaseLayout>
    </>
  ) : (
    <Redirect to="/login" />
  )}
</DocumentTitle>
Copy the code

hit<RenderRoutes />

<Switch>
  {routesConfig["menus"].map((route) = > {
    const renderComp = (route) = > {
      return (
        <Route
          key={route.path}
          path={route.path}
          exact={route.exact}
          render={(props)= > <route.component {. props} / >}
        ></Route>
      );
    };

    return route.component
      ? renderComp(route)
      : route.subs.map((r) = > renderComp(r));
  })}

  <Redirect to={routesConfig["menus"] [0].path} from="/admin"/ > {/* all missed */}
  <Redirect to="/ 404" />
</Switch>
Copy the code

LayOut LayOut

This basic layout, similar to a shelf, we know that the general background management system has

  • 404
  • login
  • There is also an Admin body with a header, sidebar, and main content area

So we need a couple of layouts, like basicLayOut with a sidebar at the top and LoginLayOut and that’s what we did.

The sidebar is generated in a dynamic loop directly from our pre-configured routing table

{
  routesConfig["menus"].map((item) = > {
    return (
      <SubMenu
        key={item.path}
        title={
          <span>
            <MailOutlined />
            <span>{item.title}</span>
          </span>
        }
      >
        {item.subs &&
          item.subs.map((sub) => {
            return (
              <Menu.Item onClick={(p)= > handleClickMenuItem(p)} key={sub.path}>
                {sub.title}
              </Menu.Item>
            );
          })}
      </SubMenu>
    );
  });
}
Copy the code

That’s right. As you may have noticed, our routing table is a MAP. It’s up to you

Component packaging

Because each page needs to locate the current position, so for the moment encapsulates the breadcrumb navigation, the complete code, please refer to the SRC/components/breadcrumb/index

<Breadcrumb style={{ margin: "12px 0"}} ><Breadcrumb.Item>
    <Link to={"/admin/dashboard"} ></Link>
  </Breadcrumb.Item>
  {FirstComp}
  {SecondComp}
</Breadcrumb>
Copy the code

Rich text editor

Form data is sent back

useEffect(() = > {
  if (form) {
    form.resetFields();
    if (addOrEdit === "Edit") {
      if (curr) {
        let par = {
          content: BraftEditor.createEditorState(curr.content),
        };
        if (curr.timerTask) {
          par["timerTask"] = moment(curr.timerTask); } form.setFieldsValue({ ... curr, ... par, }); } } } }, [addOrEdit, curr, form, location]);Copy the code

We want to content with the BraftEditor. CreateEditorState (curr. The content)

Asynchronous validation of form-item

Note here that we use async and then we can asynchronously request the interface

// Check the title
const validateTittleRule = ({ getFieldValue }) = > ({
  async validator(_, value) {
    if (value) {
      if (value.length >= 3 && value.length < 50) {}else {
        return Promise.reject("Length between xx and XX characters"); }}return Promise.reject();

    // end}});Copy the code

Data Flow management

Redux Toolkit redux-Toolkit.js.org/ configuration process, including asynchronous operation flow, is not involved in the project. This way we don’t have to configure the tedious redux-Thunk redux-saga integrated debugging tool by default. If you are interested, check out the first part of the tutorial on the website, although there are dVA Mobx and so on. If the project is using the original Redux solution, this tool is definitely a good choice

The deployment of online

Basically, each framework will tell us how to deploy. This is not the key point. Please clone the project and run it locally to see the effect.

If you have any questions, please leave a message on issues or add QQ exchange group 713593204