react 常用功能详解

107 阅读2分钟

1. create React App的使用

生成模板 npx create-react-app my-app --template typescript

1.1 定义一个组件

import React from "react";
const Robot = () => {
    return <div></div>
}
export default Robot
import React from "react";
interface RobotProps {
    name: string,
    id: string,
    email: string
}
const Robot : React.FC<RobotProps> = (props) => {
    return <div></div>
}
export default Robot

1.2 css模块加载

需要定义.d.ts文件

declare module "*.css" {
    const css: {[key:string]: string}
    export default css
}
import React from 'react';
import styles from './App.module.css'
import robots from './mockdata/robots.json'
import Robot from "./components/Robot";
​
function App() {
  return (
      <div className={styles.app}>
        <div className={styles.robotList}>
          {
            robots.map(r=> <Robot name={r.name} id={r.id} email={r.email} />)
          }
        </div>
      </div>
  );
}

npm install typescript-plugin-css-modules --save-dev

配置参数修改

tsconfig.json增加

"plugins": [
  {
    "name": "typescript-plugin-css-modules"
  }
]

1.3 state与prop

直接修改state,组件不会触发renderi函数,页面不会渲染,正确的修改方式是使用setState0

1.4 state异步

<button
    onClick={() => {
        this.setState((preStatr, preProps) => {
            return {count: preStatr.count +1}
        }, () => {
            console.log("count", this.state.count)
        })
        this.setState((preStatr, preProps) => {
            return {count: preStatr.count +1}
        }, () => {
            console.log("count", this.state.count)
        })
    }}
>
    Click
</button>

1.5 生命周期

  • Mounting:创建虚拟DOM,渲染UI
  • Updating:更新虚拟DOM,重新渲染UI
  • Mounting:创建虚拟DOM,渲染UI
  • Updating:更新虚拟DOM,重新渲染UI
  • Unmounting:删除虚拟DOM,移除UI
// 在组件创建好dom元素以后、挂载进页面的时候调用
componentDidMount() {
  fetch("https://jsonplaceholder.typicode.com/users")
    .then((response) => response.json())
    .then((data) => this.setState({ robotGallery: data }));
}
​
// * 生命周期第二阶段: 更新
// 在组件接收到一个新的 prop (更新后)时被调用。
// componentWillReceiveProps
// state getDerivedStateFromProps(nextProps, prevState){}
shouldComponentUpdate(nextProps, nextState){
 return nextState.some !== this.state.some
}
// 组件更新后调用
componentDidUpdate(){}
​
// * 生命周期第三阶段: 销毁
// 组件销毁后调用,
// 可以当作析构函数 destructor 来使用
componentWillUnmount(){}

1.6 useState

const [count, setCount] = useState<number>(0);
 <button
                onClick={() => {
                    setCount(count + 1);
                }}
            >
                Click
            </button>

1.7 useEffect

useEffect(() => {
    const fetchData = async () => {
        setLoading(true);
        try {
            const responses = await fetch(
                "https://jsonplaceholder.typicode.com/users"
            );
            // .then(response => response.json())
            // .then(data => setRobotGallery(data))
            const data = await responses.json();
            setRobotGallery(data);
        } catch (e) {
            // @ts-ignore
            setError(e.message);
        }
        setLoading(false);
    };
​
    fetchData();
}, []);

1.8 useContent

const defaultContextValue = {
    username: "阿莱克斯"
}
export const appContext = React.createContext(defaultContextValue)
 <appContext.Provider value={defaultContextValue}>
          <App />
      </appContext.Provider>

消费端

import React, {useContext} from "react";
import styles from './Robot.module.css'
import { appContext } from "../index"
interface RobotProps {
    name: string,
    id: number,
    email: string
}
const Robot : React.FC<RobotProps> = ({id, name,email}) => {
    const value = useContext(appContext)
    return <li>
        <div className={styles.cardContainer}>
            <img alt="robot" src={`https://robohash.org/${id}`} />
            <h2>{name}</h2>
            <p>{email}</p>
            <p>作者: {value.username}</p>
        </div>
    </li>
}
export default Robot

1.8 高阶组件

返回一个组件的函数

1.9 react路由

npm install --save @types/react-router-dom

2 路由

2.1获取路由参数

<Route path="/detail/:touristRouteId" component={Detail}/>
import React from "react";
import { RouteComponentProps } from "react-router-dom";
​
interface MatchParams {
  touristRouteId: string;
}
​
export const DetailPage: React.FC<RouteComponentProps<MatchParams>> = (
  props
) => {
//   console.log(props.history);
//   console.log(props.location);
//   console.log(props.match);
  return <h1>路游路线详情页面, 路线ID: {props.match.params.touristRouteId}</h1>;
};

2.2跨组件路由

withRoute

link

useRoute

3. redux

npm install redux

3.1 流程

3.1.1 初始化store

store.ts

import {createStore} from 'redux'
import LanguageReduce from './languageReduce'
export const store = createStore(LanguageReduce)
export default store

languageState.ts

export interface LanguageState {
    language: "en" | "zh";
    languageList: { name: string; code: string }[];
}
​
const defaultState: LanguageState = {
    language: "zh",
    languageList: [
        { name: "中文", code: "zh" },
        { name: "English", code: "en" },
    ],
};
// 通过action去生成一个新的state
export default (state = defaultState, action: any) => {
    if(action.type === 'changeLanguage') {
        const newState = {...state, language: action.playload}
        console.log(newState)
        return newState
    }
    return state;
};

3.2 订阅store

constructor(props: any) {
  super(props);
  const storeState = store.getState();
  this.state = {
    language: storeState.language,
    languageList: storeState.languageList,
  };
  store.subscribe(() => {
    const storeState = store.getState()
    this.setState({
      language: storeState.language
    })
  })
}
<Dropdown.Button
    style={{ marginLeft: 15 }}
    overlay={
      <Menu onClick={this.menuClickHandler}>
        {this.state.languageList.map((l) => {
          return <Menu.Item key={l.code}>{l.name}</Menu.Item>;
        })}
      </Menu>
    }
    icon={<GlobalOutlined />}
>
  {this.state.language === "zh" ? "中文" : "English"}
</Dropdown.Button>

4. 国际化

4.1安装

npm install react-i18next i18next --save

4.2 初始化

import i18n from "i18next";
import { initReactI18next } from "react-i18next";
​
import translation_en from "./en.json";
import translation_zh from "./zh.json";
​
const resources = {
  en: {
    translation: translation_en,
  },
  zh: {
    translation: translation_zh,
  },
};
​
i18n
  .use(initReactI18next) // passes i18n down to react-i18next
  .init({
    resources,
    lng: "zh",
    // keySeparator: false, // we do not use keys in form messages.welcome
    // header.slogan
    interpolation: {
      escapeValue: false, // react already safes from xss
    },
  });
​
export default i18n;

4.3 页面引入

import {withTranslation, WithTranslation} from 'react-i18next'
export class HomeComponts extends React.Component<WithTranslation> {
    render() {
        console.log(this.props.t)
        const {t} = this.props
        return <div className={styles.App}>
            <Header/>
            <div className={styles["page-content"]}>
                <Row style={{ marginTop:20}}>
                    <Col span={6}>
                        <SideMenu/>
                    </Col>
                    <Col span={18}>
                        <Carouseld/>
                    </Col>
                </Row>
                <ProductCollection title={
                    <Typography.Title>
                        {t("home_page.hot_recommended")}
                    </Typography.Title>
                } leftImage={sideImage} products={productList1} />
                <BusinessParters/>
            </div>
            <Footer/>
        </div>
    }
}
export const Home = withTranslation()(HomeComponts)

5.action工厂模式

action工厂模式

  • 新增 languageActions.ts
export const CHANGE_LANGUAGE = "changeLanguage"
interface ChangeLanguageAction {
    type: typeof CHANGE_LANGUAGE,
    playload: "zh" | "en"
}
export type LanguageActionTypes = ChangeLanguageAction
export const changeLanguageActionCreator = (laguageCode: "zh" | "en") : ChangeLanguageAction => {
    return {
        type: CHANGE_LANGUAGE,
        playload: laguageCode
    }
}
  • reduce判断
switch (action.type) {

    case CHANGE_LANGUAGE:

    i18n.changeLanguage(action.playload)

    return {...state, language: action.playload}

}

return state;
  • 引用import
import {changeLanguageActionCreator} from '../../redux/language/languageActions';

menuClickHandler = (e: any) => {

    console.log(e)

    const action = changeLanguageActionCreator(e.key)

    store.dispatch(action)

  }

6.react-redux

npm install react-redux

npm install @types/react-redux --save--dev

6.1 typescript 连接react与react-redux

6.2 类组件方式

  • index.js 引入, Provider包裹
import {Provider} from "react-redux";

import store from './redux/store'

<React.StrictMode>

        <Provider store={store}>

            <App />

        </Provider>

    </React.StrictMode>
  • 在相关组件引入connet
import {connect} from 'react-redux'
  • 构建流出属性 mapToStateProps
const mapToStateProps = (state: rootState) => {

  return {

    language: state.language,

    languageList: state.languageList

  }

}
  • 通过action构建流入
const mapDispatchToProps = (dispatch: Dispatch) => {
  return {
    changeLanguage: (code: "zh" | "en") => {
      const action = changeLanguageActionCreator(code)
      dispatch(action)
    }
  }
}
  • 返回包装
export const Header = connect(mapToStateProps,mapDispatchToProps)(withTranslation()(withRouter(HeaderComponts)))

1

2

TypeScript

  • 调用prop属性
menuClickHandler = (e: any) => {

  console.log(e)

  this.props.changeLanguage(e.key)

}

6.3 函数组件方式

  • index.js 引入, Provider包裹
<React.StrictMode>
    <Provider store={store}>
        <App />
    </Provider>
</React.StrictMode>,
import {useSelector} from "../../redux/hooks"
import {useDispatch} from "react-redux"
  • 调用
const menuClickHandler = (e: any) => {

  console.log(e)

  dispatch(changeLanguageActionCreator(e.key))

}

6.4 定义一个模块开发流程

  • 定义reduce

recommendProductsReduce.ts

import {
    recommendProductAction,
    RECOMMONEND_PRODUCTS_FAIL,
    RECOMMONEND_PRODUCTS_START,
    RECOMMONEND_PRODUCTS_SUCCESS
} from './recommendProductsActions'interface RecommendProductState {
    productList: any[],
    loading: boolean,
    error: string | null
}
​
const defaultState: RecommendProductState = {
    productList: [],
    loading: true,
    error: null
}
​
export default (state = defaultState, action: recommendProductAction) => {
    switch (action.type) {
        case RECOMMONEND_PRODUCTS_START:
            return {...state, loading: true}
        case RECOMMONEND_PRODUCTS_SUCCESS:
            return {...state, loading: false, productList: action.payload}
        case RECOMMONEND_PRODUCTS_FAIL:
            return {...state, loading: false, error: action.payload}
        default:
            return state
    }
}
  • 定义action
export const RECOMMONEND_PRODUCTS_START = "recommonend_products_start" //正在调用推荐信息

export const RECOMMONEND_PRODUCTS_SUCCESS = "recommonend_products_success" //调用推荐信息成功

export const RECOMMONEND_PRODUCTS_FAIL = "recommonend_products_end" //调用推荐信息失败

interface FetchRecommendProductStart {

    type : typeof RECOMMONEND_PRODUCTS_START

}

interface FetchRecommendProductSuccess {

    type : typeof RECOMMONEND_PRODUCTS_SUCCESS,

    payload: any

}

interface FetchRecommendProductFail {

    type : typeof RECOMMONEND_PRODUCTS_FAIL,

    payload: any

}



export type recommendProductAction = FetchRecommendProductStart

    | FetchRecommendProductSuccess

    | FetchRecommendProductFail





export const fetchRecommendProductStartCreator = () : FetchRecommendProductStart => {

    return {

        type : RECOMMONEND_PRODUCTS_START

    }

}



export const fetchRecommendProductSuccessCreator = (data: any) : FetchRecommendProductSuccess => {

    return {

        type : RECOMMONEND_PRODUCTS_SUCCESS,

        payload: data

    }

}



export const fetchRecommendProductFailCreator = (error: any) : FetchRecommendProductFail => {

    return {

        type : RECOMMONEND_PRODUCTS_FAIL,

        payload: error

    }

}
  • 类组件connect连接
import {connect} from 'react-redux'
  • 定义mapStateToProps
const mapStateToProps = (state: rootState) => {
    return {
        loading: state.recommendProducts.loading,
        productList: state.recommendProducts.productList,
        error: state.recommendProducts.error
    }
}
  • 定义mapDispatchToProps
import {Dispatch} from 'redux'
import {fetchRecommendProductStartCreator, fetchRecommendProductSuccessCreator, fetchRecommendProductFailCreator} from "../../redux/recommendProducts/recommendProductsActions"
const mapDispatchToProps = (dispatch: Dispatch) => {
    return {
        fetchStart: () => {
            dispatch(fetchRecommendProductStartCreator())
        },
        featchSuccess: (data: any) => {
            dispatch(fetchRecommendProductSuccessCreator(data))
        },
        featchFail: (error: any) => {
            dispatch(fetchRecommendProductFailCreator(error))
        },
    };
};
  • connect连接
export const Home = connect(mapStateToProps, mapDispatchToProps)(withTranslation()(HomeComponts))
  • 请求调用
async componentDidMount() {

    this.props.fetchStart()

     try {

         const { data } = await axios.get("http://123.56.149.216:8080/api/productCollections",{

             headers : {

                 "x-1c0de":"FB80558A73FA658E"

             }

         })

         this.props.featchSuccess(data)

     }catch (error: any) {

         this.props.featchFail(error.message)

     }



 }

7.远程请求

npm install axios

8.redux中间件

可以使用在store里处理副作用,多个组件可以共享使用

8.1案例

  • 引入thunk, applyMiddleware
import {createStore, combineReducers,applyMiddleware} from 'redux'

import thunk from 'redux-thunk'

export const store = createStore(rootReducer, applyMiddleware(thunk))
  • 定义action构造方法
export const giveMeDataActionCreator = ():

    ThunkAction<void, rootState, unknown, recommendProductAction> =>

    async (dispatch, getState) => {

    try {

        dispatch(fetchRecommendProductStartCreator())

        const { data } = await axios.get("http://123.56.149.216:8080/api/productCollections",{

            headers : {

                "x-1c0de":"FB80558A73FA658E"

            }

        })

        fetchRecommendProductSuccessCreator(data)

    }catch (error) {

        dispatch(fetchRecommendProductFailCreator(error.message))

    }



}
  • 使用action
import {giveMeDataActionCreator} from "../../redux/recommendProducts/recommendProductsActions"

const mapDispatchToProps = (dispatch: any) => {

    return {

        giveMeData: () => {

            dispatch(giveMeDataActionCreator())

        }

    };

};

componentDidMount() {

       this.props.giveMeData()



    }

8.2自定义中间件

公式: const middleware (store)=>(next)=>(action)=>{}

actionLog.ts

import {Middleware} from 'redux'
export const actionLog: Middleware =  (store)=>(next)=>(action)=>{
    console.log("当前state" + JSON.stringify(store.getState()))
    console.log("action" + JSON.stringify(action))
    next(action)
    console.log("state更新" + JSON.stringify(store.getState()))
}

引入

import {actionLog} from './middlewares/actionLog'
export const store = createStore(rootReducer, applyMiddleware(thunk, actionLog))

9.redux-toolkit

npm install @reduxjs/toolkit

9.1 使用方法一,自己处理回调

  • 构建slice
import {createSlice, PayloadAction} from "@reduxjs/toolkit"

interface ShopDetail {

    loading: boolean,

    data: any,

    error: string | null

}

const initialState: ShopDetail = {

    loading: false,

    data: null,

    error: null

}

export const ShopDetailSlice = createSlice({

    name : "shopDetail",

    initialState,

    reducers: {

        featchStart: (state) => {

            state.loading = true

        },

        featchSuccess: (state, action) => {

            state.loading = false

            state.data = action.payload

        },

        featchFail: (state, action: PayloadAction<string | null>) => {

            state.loading = false

            state.error = action.payload

        }

    }

})
  • 定义configureStore
export const store = configureStore({

    reducer: rootReducer,

    middleware: getDefaultMiddleware => [...getDefaultMiddleware(), actionLog],

    devTools: true

})
  • 调用接口
useEffect(() => {
    dispatch(ShopDetailSlice.actions.featchStart);
    // 获取产品数据
    const featchDate = async () => {
        try {
            const resp = await axios.get(`http://localhost:8199/api/shop/queryById/${touristRouteId}`, {
                headers : {
                    "Authorization":"111"
                }
            });
           dispatch(ShopDetailSlice.actions.featchSuccess(resp.data.data.pmsShop))
        } catch (error) {
            dispatch(ShopDetailSlice.actions.featchFail(error))
        }
    }
    featchDate();
},[])

9.2 使用方法二,自动处理回调结果

  • 构建slice
import {createSlice, PayloadAction, createAsyncThunk} from "@reduxjs/toolkit"
import axios from "axios";
interface ShopDetail {
    loading: boolean,
    data: any,
    error: string | null
}
const initialState: ShopDetail = {
    loading: false,
    data: null,
    error: null
}
export const getShopDetail = createAsyncThunk("shop/shopDetail",
      async (touristRouteId:string, ThunkApi) => {
          const resp = await axios.get(`http://localhost:8199/api/shop/queryById/${touristRouteId}`, {
              headers : {
                  "Authorization":"111"
              }
          });
      return resp.data.data.pmsShop;
})
export const ShopDetailSlice = createSlice({
    name : "shopDetail",
    initialState,
    reducers: {
​
    },
    extraReducers: {
        [getShopDetail.pending.type]: (state) => {
            state.loading = true
        },
        [getShopDetail.fulfilled.type]: (state, action) => {
            state.loading = false
            state.data = action.payload
        },
        [getShopDetail.rejected.type]: (state, action: PayloadAction<string | null>) => {
            state.loading = false
            state.error = action.payload
        }
    }
})
  • 定义configStore
export const store = configureStore({

    reducer: rootReducer,

    middleware: getDefaultMiddleware => [...getDefaultMiddleware(), actionLog],

    devTools: true

})
  • 调用接口
import {getShopDetail} from "../../redux/shopDetail/slice"

 useEffect(() => {

        dispatch(getShopDetail(touristRouteId));

    },[])