Css modular

  • Methods a
    • Rename style.css to style.module.css
    • useimport style from './style.module.cssBring about
    • use<div className={style.xxx}>To use styles
  • Way 2
    • npm run ejectExposed webpack. Config. Js
    • searchcssRegexAdd the configuration at the bottom
    • Use the same style as the first (no need to change style.css to style.module.css)
/ / project/config/webpack. Config. Js
// 1. On cssRegex, configure modules and exclude
// 2. Add a cssRegex and configure include(important, do not add global style does not take effect bug)
// 3. Configure localIdentName in cssModuleRegex

{
  test: cssRegex,
  use: getStyleLoaders({
    importLoaders: 1.//1. Add modules configuration names
    modules: {localIdentName: "[path]-[name]-[local]-[hash:base64:6]"
    },
    sourceMap: isEnvProduction
      ? shouldUseSourceMap
      : isEnvDevelopment,
  }),
  //2. Configure global styles (this folder is not modularized)
  exclude:[
    path.join(__dirname,".."."node_modules"),
    path.join(__dirname,".."."src/assets/css/common"),
    path.join(__dirname,".."."src/components")],sideEffects: true,},//3. Add a loader configuration (without this section, the global style will not take effect)-------
{
  test:cssRegex,
  use: ["style-loader"."css-loader"].include:[
    path.join(__dirname,".."."node_modules"),
    path.join(__dirname,".."."src/assets/css/common"),
    path.join(__dirname,".."."src/components")]},//---------------------------------------
{
  test: cssModuleRegex,
  use: getStyleLoaders({
    importLoaders: 1.sourceMap: isEnvProduction
      ? shouldUseSourceMap
      : isEnvDevelopment,
    modules: {
      // getLocalIdent: getCSSModuleLocalIdent,
      //4. Configure modular naming in cssModuleRegex
      localIdentName: "[path]-[name]-[local]-[hash:base64:6]"}})},Copy the code

The use of the story

Using the step

  • create
/ / the root component
//1. Introduce redux and react-redux
import { createStore } from 'redux'
import { Provider } from 'react-redux'
//2. Prepare data state and method action
function counterReducer (state = { count: 4 }, { type, payload }) {
  switch (type) {
    case 'INC':
      return Object.assign({}, state, payload)
    case 'DEC':
      return Object.assign({}, state, payload)
    default:
      return state

  }
}
//3. Store the data state and method action in the redux repository
let store = createStore(counterReducer)

//4. Inject repository: Use Provider to wrap around the root component
ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>.document.getElementById('root'));Copy the code
  • use
import React, { Component } from 'react'
import { connect } from 'react-redux'
class Index extends Component {
    constructor(props) {
        super(a)this.state = {
            num: props.state.count
        }
    }

    increment () {
        /* this.props. Dispatch ({type,payload}) type: /* this.props. Dispatch ({type,payload}) type
        this.props.dispatch({ type: 'INC'.payload: { count: + +this.state.num } })
    }

    decrement () {
        this.props.dispatch({ type: 'DEC'.payload: { count: -this.state.num } })
    }
    render () {
        return (
            <div>Home page<h3>Quantity: {this. State. Num}</h3>
                <button onClick={this.decrement.bind(this)}>-</button>
                <button onClick={this.increment.bind(this)}>+</button>
            </div>)}}export default connect(state= > {
    return {
        state: state
    }
})(Index)

Copy the code

The use of the Saga

  • create
    • fromredux-saga/effectsIntroduce methods
    • Create an asynchronous methodfunction* saga
    • Define a methodfunction* xxx, put asynchronous methods into it using takeLatest
    • Export the defined saga
// src/saga/index.js
import { call, put, takeLatest } from 'redux-saga/effects'
import Api from '. /.. /apis'

/**
* call(fn,argument)
*/
function* fetchProjectInfo({ payload }) {
    const res = yield call(Api.fetchProjectInfo, payload.workspaceId) // Call (fn,arg), interface parameters need to be written behind, and interface method level, are call parameters
    yield put({ type: 'FETCH_PROJECT_INFO'.payload: res })
}

function* rootSaga() {
    yield takeLatest('SAGA_PROJECT_INFO', fetchProjectInfo)
}

export default rootSaga
Copy the code
  • use
    • The introduction of createSagaMiddleware
    • Execute const sagaMiddleware = createSagaMiddleware()
    • The introduction of applyMiddleware
    • Inject Store: applyMiddleware(sagaMiddleware)
// src/store/index.js

import { createStore, applyMiddleware } from 'redux'
import reducers from './reducers'

import createSagaMiddleware from 'redux-saga'
import rootSaga from '.. /saga'

const sagaMiddleware = createSagaMiddleware()

const store = createStore(
    reducers,
    applyMiddleware(sagaMiddleware)
)

sagaMiddleware.run(rootSaga)
export default store
Copy the code

react + typescript

// Create the project
// create-react-app typescript-react-app --typescript

// Open the project
// cd typescript-react-app

// To install dependencies, yarn is recommended
//yarn

/ / run
//npm run start
Copy the code

Data sharing

context

Warehouse: github.com/santa945/ty…

Branches: feature/context

The context to create
  • Create a context: react.createcontext ()
  • Add a default value: defaultValue = {key: STR | number | boolen | fn |… }
  • Deconstruct Provider and Consumer
  • Generate a class component
  • The render function returns with the outermost package
  • The Provider value property is an object with defaultValue as a key:

import React,{Component} from 'react'
/** * 1. Create a context: React. CreateContext () * 2. Add a default value: defaultValue = {key: STR | number | boolen | fn |... } * 3. Deconstruct Provider and Consumer * 4. 
       */

 interface IProps{
    children: ReactNode
 }

 type IState={
     auth: boolean,
     username: string,
 }
const defaultValue = {
    auth:false.username:' '.signin:() = >{}}let {Provider,Consumer:AppConsumer} = React.createContext(defaultValue)

class AppProvider extends Component<IProps.IState> {
    constructor(props:IProps){
        super(props)
        this.state={
            auth:false.username:' '
        }
    }
    signIn = () = >{
        this.setState({
            auth:true.username:'John'})}render(){
        return (
            <Provider value={{
                auth:this.state.auth.username:this.state.username.signin:() = >this.signIn()
            }}>
                {
                    this.props.children
                }
            </Provider>)}}export {
    AppProvider,// Export the package on the component that uses the context
    AppConsumer// Export the package to the component that uses the data in the context
}

Copy the code
The context used
  • AppProvider on the external package of the component that uses the context
  • AppConsumer on the component package that needs to consume the data shared by the context
//App.tsx
import {AppProvider} from '.. /src/context/AppContext'

function App() {
  return (
    <AppProvider>
      <div className="App">
        <User></User>
      </div>
    </AppProvider>
  );
}

//users/Index.tsx

import Welcome from './Welcome'
import Login from './Login'
import { AppConsumer} from ". /.. /.. /context/AppContext"

export default class Index extends Component {
    render() {
        return (
            <AppConsumer>
                {
                    ({auth})=>{
                        return auth ? <Welcome></Welcome> : <Login></Login>}}</AppConsumer>)}}//Login.tsx
import {AppConsumer} from '. /.. /.. /context/AppContext'
export default class Login extends Component {
    render() {
        return (
            <AppConsumer>
                {
                  ({signin})=>{
                      return <button onClick={signin}>login</button>}}</AppConsumer>)}}Copy the code

Redux

Warehouse: github.com/santa945/ty…

Branches: feature/story

// Install dependencies
//yarn add redux react-redux

// The react-redux type declaration file needs to be installed
// yarn add @types/react-redux
Copy the code
The creation of a store
  • Create store/index.ts in the root folder
  • Create a Store and stuff it with reducers
//store/index.ts
import { createStore} from 'redux'
import reducers from './reducers'
const store = createStore(reducers);

export default store;
Copy the code
Creation of reducers

Normally, different modules will have their own reducers, so use modularization to create the reducers folder under Store and merge each reducers with index.ts

  • Create a single reducers as a function that accepts a state and an action
  • Create merged channel reducers/index.ts, introduce combineReducers, receive each individual channel reducers, and export the merged reducers
//store/reducers/index.ts
import { combineReducers} from 'redux'
import todos from './todo'

export default combineReducers({
    todos
})

//store/reducers/todo.ts
const TodoReducers = (state,action) = >{
    / /...
}
export default TodoReducers;
Copy the code
Definitions of types and aciton
  • Create two separate folders under the Store folder and put the types in
  • Separate to reducers using types and action types
// store/types/index.ts
export interface ITodo {
    id: number,
    text: string,
    completed: boolean
}
//------------------------------------------------
//store/action/index.ts
const ADD_TODO = 'ADD_TODO'
const TOGGLE_TODO = 'TOGGLE_TODO'


export interface ITodoAciton {
    type: typeof ADD_TODO | typeof TOGGLE_TODO ,
    id: number,
    text: string
}


//------------------------------------------------

//store/reducers/todo.ts
import {ITodo} from '.. /types'
import {ITodoAciton} from '.. /action'

const defaultValue = {
     id:0.text:'hello'.completed:false
}
const todoReducers = (state:Array<ITodo>=[defaultValue],action:ITodoAciton) = >{
    switch (action.type){
        case 'ADD_TODO':
            return [
                ...state,
                {
                    id:action.id,
                    text:action.text,
                    completed:false}]default:
            return state

    }
}

export default todoReducers
Copy the code
Create the connect
//pages/todo/connect.ts
import { connect } from 'react-redux'
import { ITodo } from '.. /.. /store/types'
import { Dispatch} from 'redux'

type Todos = {
    todos: Array<ITodo>
}

const mapStateToProps = (state:Todos) = >{
    console.log('state:',state);
    
    return {
        todos: state.todos
    }
}

const mapDispatchToProps = (dispatch:Dispatch) = >{
    return {
        add:() = >{}}}export default connect(mapStateToProps,mapDispatchToProps)
Copy the code
Connect the Redux to the component using Connect
  • Equivalent to a higher-order component
//pages/todo/visibleList.tsx

import React, { Component } from 'react'
import TodoItem from '.. /.. /components/TodoItem'
import connect from './connect'
import { ITodo } from '.. /.. /store/types'

type IProps = {
    todos: Array<ITodo>
}
class VisibleList extends Component<IProps> {
    render() {
        return (
            <ul>{// here props is the result of connect, obtained from reducers // here this.props. Todos corresponds to combineReducers({todos}), The name is the same as the combineReducers object this.props.todos.map(item=>{return<TodoItem {. item} ></TodoItem>})}</ul>)}}export default connect(VisibleList)
Copy the code
Event distribution changes store
  • Components connect to Redux using Connect
  • Use this.props. Fn () to get the methods in connect.tsx
  • Connect defines methods to trigger a store
//pages/todo/AddTodo.tsx

import React, { Component } from 'react'
import connect from './connect'
let textRef:React.RefObject<HTMLInputElement> = React.createRef();

type P = {
    add:(text:string) = >void
}
class AddTodo extends Component<P> {
    handleClick=() = >{
        // Get the data in the input. There are two ways: controlled and uncontrolled. Ref is uncontrolled and uncontrolled
        let txt = (textRef.current as HTMLInputElement).value
        // Call the add method, which is the add method in connect.ts
        this.props.add(txt)
    }
    render() {
        return (
            <div>
                <input type="text" ref={textRef} />
                <button onClick={this.handleClick}>add</button>
            </div>)}}export default connect(AddTodo)

//---------------------------------------------------

//pages/todo/connect.ts
import { connect } from 'react-redux'
import { ITodo } from '.. /.. /store/types'
import { Dispatch} from 'redux'

type Todos = {
    todos: Array<ITodo>
}

let id = 1;
const mapStateToProps = (state:Todos) = >{
    console.log('state:',state);
    return {
        todos: state.todos
    }
}

const mapDispatchToProps = (dispatch:Dispatch) = >{
    return {
        // The component calls this method as this.props. Add ('123'), passing in the parameter
        add:(txt:string) = >{
            dispatch({ // The event is sent to ADD_TODO in store, passing the argument
                type:"ADD_TODO".id: id++,
                text: txt
            })
        }
    }
}

export default connect(mapStateToProps,mapDispatchToProps)
Copy the code