react学习开发流程

  1. 创建项目
yarn create react-app project-name
  1. 覆盖 create-react-app webpack 配置, 不需要 eject
yarn add react-app-rewired customize-cra -D
  1. 修改 package.json
"scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-scripts eject"
  },
  1. 创建 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,
    }),
)
  1. 添加 antd
yarn add antd
  1. 添加 less 支持
yarn add less less-loader -D
  1. 按需加载
yarn add babel-plugin-import -D
  1. 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)', // 浮层阴影
}
  1. 装饰器模式支持
yarn add @babel/plugin-proposal-decorators -D
  1. 构建目录
mkdir src/components src/views src/routes src/reducers src/actions
  1. 添加 react-router
yarn add react-router-dom
  1. 添加基本视图页面
-views
    -Home
        -index.js
    -Article
        -index.js
        -Edit.js
  1. 编写路由
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
    },
  1. 在 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')
)
  1. 在主组件 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
  1. 添加延迟加载
yarn add react-loadable
  1. 编写 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,
}
  1. 引入 antd 组件编写页面
  2. 添加 axios
yarn add axios
  1. 获取接口数据渲染页面
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)
}
  1. 添加 redux react-redux redux-thunk
yarn add redux react-redux redux-thunk
  1. 创建 src/store.js 作为全局存储
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import rootReducer from './reducers'

export default createStore(
    rootReducer,
    applyMiddleware(thunk)
)
  1. 在 src/index.js 引入 store 并使用 Provider 高阶组件传递
import { Provider } from 'react-redux'
import store from './store'

<Provider store={store}>
       ...
</Provider>
  1. 创建 ./actions/actionType.js 定义类型
export default {
    MARK_NOTIFICATION_AS_READ_BY_ID: 'MARK_NOTIFICATION_AS_READ_BY_ID',
    ...
    GET_NOTIFICATIONS: 'GET_NOTIFICATIONS',
};
  1. 创建 ./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())
        })
    }
}

  1. 创建 ./reducers/index.js 合并多个 reducers
import { combineReducers } from 'redux'
import notifications from './notifications'

export default combineReducers({
    notifications
})
  1. 创建 ./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
    }
}
  1. 在页面使用获取全局属性
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)

你可能感兴趣的:(react)