react学習開発プロセス

52250 ワード

  • プロジェクトの作成
  • yarn create react-app project-name
    
  • create-react-app webpack構成を上書きし、eject
  • を必要としない
    yarn add react-app-rewired customize-cra -D
    
  • packageを変更します.json
  • "scripts": {
        "start": "react-app-rewired start",
        "build": "react-app-rewired build",
        "test": "react-app-rewired test",
        "eject": "react-scripts eject"
      },
    
  • config-overridesを作成する.js
  • const {
        override,
        addLessLoader, 
        fixBabelImports, //  
        addDecoratorsLegacy //  
    } = require('customize-cra')
    
    const modifyVars = require('./theme') //  
    
    module.exports = override(
        addLessLoader({
            javascriptEnabled: true,
            modifyVars
        }),
        addDecoratorsLegacy(),
        fixBabelImports('import', {
            libraryName: 'antd',
            libraryDirectory: 'es',
            style: true,
        }),
    )
    
  • antd
  • を追加
    yarn add antd
    
  • 追加lessサポート
  • yarn add less less-loader -D
    
  • オンデマンドロード
  • yarn add babel-plugin-import -D
    
  • theme.js
  • module.exports = {
        '@primary-color': ' #1890ff', //  
        '@link-color': ' #1890ff', //  
        '@success-color': ' #52c41a', //  
        '@warning-color': ' #faad14', //  
        '@error-color': ' #f5222d', //  
        '@font-size - base': ' 14px', //  
        '@heading-color': ' rgba(0, 0, 0, 0.85)', //  
        '@text-color': ' rgba(0, 0, 0, 0.65)', //  
        '@text-color - secondary ': ' rgba(0, 0, 0, .45)', //  
        '@disabled-color ': ' rgba(0, 0, 0, .25)', //  
        '@border-radius - base': ' 4px', //  / 
        '@border-color - base': ' #d9d9d9', //  
        '@box-shadow - base': ' 0 2px 8px rgba(0, 0, 0, 0.15)', //  
    }
    
  • 装飾モードは
  • をサポートする.
    yarn add @babel/plugin-proposal-decorators -D
    
  • 構築ディレクトリ
  • mkdir src/components src/views src/routes src/reducers src/actions
    
  • react-router
  • を追加
    yarn add react-router-dom
    
  • 基本ビューページ
  • を追加
    -views
        -Home
            -index.js
        -Article
            -index.js
            -Edit.js
    
  • 作成ルーティング
  • import {
        Dashboard,
        Login,
        NotFound,
    } from '../views'
    
    export const mainRouter = [
        {
            pathname: '/login',
            component: Login
        },
        {
            pathname: '/404',
            component: NotFound
        },
    ]
    
    export const adminRouter = [
        {
            pathname: '/admin/dashboard',
            component: Dashboard
        },
    
  • はindexにあります.jsにはルーティング
  • が導入されている
    import React from 'react'
    import { render } from 'react-dom'
    import { HashRouter as Router, Route, Switch, Redirect } from 'react-router-dom'
    import { mainRouter } from './routes'
    import App from './App'
    
    render(
        <Router>
            <Switch>
                <Route path='/admin' render={routeProps => {
                    // TODO:  
                    return <App {...routeProps} />
                }} />
                {
                    mainRouter.map(route => <Route
                        key={route.pathname}
                        path={route.pathname}
                        component={route.component}
                    />)
                }
                <Redirect to='/admin' from='/' exact />
                <Redirect to='/404' />
            </Switch>
        </Router>,
        document.getElementById('root')
    )
    
  • は、メインコンポーネントにおいてApp.jsではルーティング
  • を使用する
    import React from 'react'
    import { Route, Switch, Redirect } from 'react-router-dom'
    import { adminRouter } from './routes'
    const App = (props) => (
        <div>
            <div> </div>
            <Switch>
                {
                    adminRouter.map(route => (
                        <Route
                            key={route.pathname}
                            exact={route.exact}
                            path={route.pathname}
                            render={routerProps => (
                                <route.component
                                    {...routerProps}
                                />
                            )}
                        />
                    ))
                }
                <Redirect to={adminRouter[0].pathname} from='/admin' exact />
                <Redirect to='/404' />
            </Switch>
        </div>
    )
    
    export default App
    
  • 追加遅延ロード
  • yarn add react-loadable
    
  • views/indexを記述する.js遅延ロードコンポーネント
  • import { Loading } from '../components'
    import Loadable from 'react-loadable'
    
    const loadindComponent = (loader, loading = Loading) => (
        Loadable({
            loader,
            loading
        })
    )
    
    const Dashboard = loadindComponent(
        () => import('./Dashboard'),
    )
    
    const Login = loadindComponent(
        () => import('./Login'),
    )
    
    export {
        Dashboard,
        Login,
    }
    
  • antdコンポーネント作成ページ
  • を導入する.
  • axios
  • を追加
    yarn add axios
    
  • インタフェースデータレンダリングページ
  • を取得する.
    import Axios from "axios";
    
    const isDev = process.env.NODE_ENV === 'development'
    
    const ajax = Axios.create({
        baseURL: isDev ? 'http://rap2api.taobao.org/app/mock/244403/' : ''
    })
    
    ajax.interceptors.request.use((config) => {
        config.params = Object.assign({}, config.params, {
            Authorization: 'Bearer ...'
        })
        return config
    }, err => {
        console.log(err)
    })
    
    ajax.interceptors.response.use((resp) => {
        return resp.data.data
    }, (error) => {
        if (error.response) {
            // The request was made and the server responded with a status code
            // that falls out of the range of 2xx
            console.log(error.response.data);
            return Promise.reject(error.response.data)
            // return error.response.data
        } else if (error.request) {
            // The request was made but no response was received
            // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
            // http.ClientRequest in node.js
            console.log(error.request);
        } else {
            // Something happened in setting up the request that triggered an Error
            console.log('Error', error.message);
        }
        return Promise.reject(error)
    })
    
    export const getArticles = (offset = 0, limit = 10) => {
        return ajax.get('/api/v1/article', { params: { offset, limit } })
    }
    
    export const delArticles = (id) => {
        return ajax.delete('/api/v1/article/' + id)
    }
    
  • redux react-redux redux-thunk
  • を追加
    yarn add redux react-redux redux-thunk
    
  • src/storeを作成する.jsはグローバルストレージとして
  • import { createStore, applyMiddleware } from 'redux'
    import thunk from 'redux-thunk'
    import rootReducer from './reducers'
    
    export default createStore(
        rootReducer,
        applyMiddleware(thunk)
    )
    
  • はsrc/indexにある.jsはstoreを導入し、Provider高次コンポーネントを使用して
  • を伝達する.
    import { Provider } from 'react-redux'
    import store from './store'
    
    <Provider store={store}>
           ...
    </Provider>
    
  • 作成./actions/actionType.js定義タイプ
  • export default {
        MARK_NOTIFICATION_AS_READ_BY_ID: 'MARK_NOTIFICATION_AS_READ_BY_ID',
        ...
        GET_NOTIFICATIONS: 'GET_NOTIFICATIONS',
    };
    
  • 作成./actions/notifications.js配信動作
  • import actionType from './actionTypes'
    import { getNotifications } from '../requests'
    
    export const markNotificationAsReadByid = (id) => {
        return dispatch => {
            dispatch(startNotification())
            setTimeout(() => {
                dispatch({
                    type: actionType.MARK_NOTIFICATION_AS_READ_BY_ID,
                    payload: { id }
                })
                dispatch(endNotification())
            }, 2000)
    
        }
    }
    ...
    export const endNotification = () => {
        return {
            type: actionType.END_NOTIFICATION_LODING,
        }
    }
    
    export const notifications = () => {
        return dispatch => {
            dispatch(startNotification())
            getNotifications().then((resp) => {
                dispatch({
                    type: actionType.GET_NOTIFICATIONS,
                    payload: {
                        list: resp.list
                    }
                })
            }).finally(() => {
                dispatch(endNotification())
            })
        }
    }
    
    
  • 作成./reducers/index.js複数のreducers
  • をマージ
    import { combineReducers } from 'redux'
    import notifications from './notifications'
    
    export default combineReducers({
        notifications
    })
    
  • 作成./reducers/notifications.js定義reducerは異なるactionsを操作する
  • import actionTypes from '../actions/actionTypes'
    
    const initState = {
        isLoading: true,
        list: []
    }
    
    export default (state = initState, action) => {
        switch (action.type) {
            case actionTypes.START_NOTIFICATION_LODING:
                return {
                    ...state,
                    isLoading: true
                }
            case actionTypes.GET_NOTIFICATIONS:
                return {
                    ...state,
                    list: action.payload.list,
                }
            case actionTypes.MARK_NOTIFICATION_AS_READ_BY_ID:
                return {
                    ...state,
                    list: state.list.map(item => {
                        if (item.id === action.payload.id)
                            item.hasRead = true
                        return item
                    })
                }
            ...
            case actionTypes.END_NOTIFICATION_LODING:
                return {
                    ...state,
                    isLoading: false
                }
            default:
                return state
        }
    }
    
  • ページ使用取得グローバル属性
  • import { connect } from 'react-redux'
    import { markNotificationAsReadByid, markAllNotificationsAsRead } from '../../actions/notifications'
    
    const mapStateToProps = state => {
        const {
            list, isLoading
        } = state.notifications
        return {
            list, isLoading
        }
    }
    
    function Notification(props) {
        return (
            <Spin spinning={props.isLoading} >
                <Card
                    title=' '
                    bordered={false}
                    extra={
                        <Button
                            disabled={props.list.every(item => item.hasRead === true)}
                            onClick={() => {
                                props.markAllNotificationsAsRead()
                            }}
                        > </Button>
                    }
                >
                    <List
                        itemLayout="horizontal"
                        dataSource={props.list}
                        renderItem={item => (
                            <List.Item
                                extra={
                                    item.hasRead ? null : <Button
                                        onClick={() => {
                                            props.markNotificationAsReadByid(item.id)
                                        }}
                                    > </Button>
                                }
                            >
                                <List.Item.Meta
                                    avatar={<Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />}
                                    title={<Badge dot={!item.hasRead} >{item.title}</Badge>}
                                    description={item.desc}
                                />
                            </List.Item>
                        )}
                    />
                </Card>
            </Spin>
        )
    }
    
    export default connect(mapStateToProps, { markNotificationAsReadByid, markAllNotificationsAsRead })(Notification)