предисловие
Раньше я использовал vue для разработки, поэтому решил перейти на React через год, так что я некоторое время возился с React после года, и я вижу результаты.
Я собирался написать что-то вродеVue имитирует сегодняшние заголовкиЯ начинал с такого проекта, а потом подумал, что может быть лучше написать фоновый менеджмент. Так и начал возиться.
Используйте модули экологической цепочки, связанные с реакцией:
react
react-dom
-
react-router-dom
: После react-router4 вроде использует эту штуку -
react-transition-group
: для анимации -
redux
: используется для управления глобальным состоянием -
react-redux
: используется для управления глобальным состоянием -
redux-actions
: Используется для создания действий и не пишет switch/case или if/else при создании связанных редьюсеров, в основном для удобства. -
redux-thunk
:redux
промежуточное ПО для обработки наших асинхронных действий -
antd
: более часто используемая библиотека реактивного пользовательского интерфейса, которую я нашел случайно.
Основные из них, связанные с реакцией, это Что касается конфигурации webpack, то она в принципе мало чем отличается от предыдущей конфигурации vue.
Объяснение каталога файлов:
-
build
: используется для размещения конфигурации о веб-пакете -
config
: конфигурация проекта -
src
: исходный код -
static
: статический ресурс -
.babelrc
: конфигурация бабеля -
postcss.config.js
: конфигурация css
Я не буду говорить о других каталогах, а в основном представлю одинsrc
структура каталогов под
-
actions
: Поместите место, связанное с действием, в редукцию. -
reducers
: Поместите место, связанное с редуктором, в редукцию. -
assets
: статические ресурсы проекта -
components
: часто используемые общедоступные компоненты. -
router
: конфигурация, связанная с маршрутизацией -
store
: редукционная конфигурация -
styles
: общедоступный файл стиля -
utils
: Инкапсуляция классов инструментов -
view
: Основная структура всех страниц -
main.js
: файл входа в проект -
config.js
: конфигурация публичного свойства
1. Несколько способов написания реакции
- React.createClass
import React from 'react'
const MyComponent = React.createClass({
render () {
return (
<h2>我是React.createClass生成的组件</h2>
)
}
})
- React.createClass будет самостоятельно связывать методы функций (в отличие от React.Component, который связывает только те функции, о которых нужно заботиться), вызывая ненужные накладные расходы на производительность и увеличивая вероятность устаревшего кода.
- Миксины React.createClass не являются естественными и интуитивно понятными;
- React.Component
import React from 'react'
class MyComponent from React.Component {
render () {
return (
<h2>我是React.Component生成的组件</h2>
)
}
}
- Необходимо вручную привязать этот указатель
- Форма React.Component очень подходит для компонентов более высокого порядка (компоненты более высокого порядка — HOC), она показывает более мощные функции, чем примеси, в более интуитивно понятной форме, а HOC — это чистый JavaScript, не беспокойтесь о том, что их забросят.
- Функциональные компоненты без состояния
import React from 'react'
const MyComponent = (props) => (
<h2>我是无状态函数式组件</h2>
)
ReactDOM.render(<MyComponent name="Sebastian" />, mountNode)
- Создание компонентов без состояния делает код более читаемым, сокращает много избыточного кода и сводит его только к одному методу рендеринга, что значительно повышает удобство написания компонента.
- Компоненты не создаются, а общая производительность рендеринга повышается.
- Компонент не может получить доступ к этому объекту
- Компонент не имеет доступа к методам жизненного цикла
- Компоненты без состояния могут получить доступ только к входным реквизитам, те же реквизиты получат тот же результат рендеринга без побочных эффектов.
2. Перехват маршрута
Долго перехватывал роутинг, хотел найти хук-функцию, похожую на beforeRouter из vue, но не нашел.
а затем найтиhistory
модуль, я обнаружил что у этой штуки есть метод для мониторинга маршрута.Я использовал его в начале, но когда я вдруг врубился в режим хеширования для разработки, я обнаружил, что черезhistory.push(path, [state])
Возникла проблема при установке свойства состояния.Вроде эта штука может устанавливать свойство состояния только для режима истории, но некоторые мои вещи заходят с установкой свойства состояния, поэтому я отказался от этого метода и искал новый метод.
Позже было обнаружено, что корневой путь можно отслеживать с помощьюcomponentWillReceiveProps
Функция крюка может обеспечить эффект мониторинга.
Эта функция хука будет запускаться всякий раз, когда меняются реквизиты, потому что каждый раз, когда маршрут переключаетсяlocation
изpathname
Это всегда по-разному, поэтому, пока путь переключается, эта функция ловушки будет активирована. Эта штука может легко вызвать бесконечный цикл, так что не забывайте использовать свое суждение.
class MainComponents extends React.Component {
componentWillMount () { // 第一次进来触发
this.dataInit(this.props)
}
componentWillReceiveProps(nextProps){ // 以后每次变化props都会触发
// 如果死循环了 可能是某个属性设置会更新props上属性,所以导致一直循环,这个时候记得做好判断
this.dataInit(nextProps)
}
render () {
// 404
if (!isExistPath(allRoutes, pathname)) return <Redirect to='/error/404'/>
//当前路径路由信息
let currRoute = getRoute(allRoutes, pathname)
// 非白名单验证
if (!whiteList.some(path => path === pathname)) {
// 登录验证
if (!Cookie.get('Auth_Token')) {
return <Redirect to={{ pathname: '/login' }} />
}
// 获取用户信息
if (!user) {
this.getUserInfo(() => {
this.setRoutesByRole(this.props.user.roles)
})
}
}
// 401
if (user && currRoute) {
if (!isAuth(currRoute.role, user)) return <Redirect to='/error/401'/>
}
// 网页title
document.title = currRoute.name
}
}
3. Централизованные настройки маршрутизации
Любой, кто использовал Vue, знает, что мы обычно передаемnew Router({routes})
для централизованного управления таблицей маршрутизации. Но реагирующий маршрутизатор, похоже, не может установить его таким образом. Последняя версия, кажется, даже не работает с вложением.
Поэтому я начал просто создавать централизованную версию. Но позже я увидел плагин, который кажется управляемым.react-router-config, но я еще не пробовал, и я не знаю, возможно ли это.
// 路由表
const allRoutes = [
{
path: '/auth',
login: true,
layout: true,
icon: 'user',
name: '权限管理',
role: ['admin'],
component: _import_views('Auth')
},
{
path: '/error',
login: true,
layout: true,
icon: 'user',
name: 'ErrorPage',
redirect: '/error/404',
children: [
{ path: '/error/404', component: _import_views('Error/NotFound'), name: '404'},
{ path: '/error/401', component: _import_views('Error/NotAuth'), name: '401'}
]
}
...
]
// 根目录
<BrowserRouter>
<Route path="/" component={MainComponents}/>
</BrowserRouter>
// MainComponents
class MainComponents extends React.Component {
render () {
return (
<Switch>
{renderRouteComponent(allRoutes.filter(route => !route.layout))} //不需要侧边栏等公共部分的路由页面
<Route path="/" component={ComponentByLayout}/>
</Switch>
)
}
}
// ComponentByLayout
const ComponentByLayout = ({history}) => (
<Layout history={history}>
<Switch>
{renderRouteComponent(allRoutes.filter(route => route.layout))}
</Switch>
</Layout>
)
// 路由渲染
const RouteComponent = route => <Route key={route.path} exact={route.exact || false} path={route.path} component={route.component} />
const renderRouteComponent = routes => routes.map((route, index) => {
return route.children ? route.children.map(route => RouteComponent(route)) : RouteComponent(route)
})
4. Динамически генерировать маршруты на основе разрешений пользователя
Я хочу создавать разные боковые панели в соответствии с разными разрешениями пользователей.
{
path: '/auth',
login: true,
layout: true,
icon: 'user',
name: '权限管理',
role: ['admin'],
component: _import_views('Auth')
}
В соответствии с этой информацией о роли маршрутизации сопоставьте информацию о роли пользователя для отображения и скрытия.
Таким образом, таблица маршрутизации и боковая панель, соответствующие этому пользователю, отфильтровываются (боковая панель создается на основе таблицы маршрутизации).
Но есть проблема, потому что нам нужно войти в систему, чтобы узнать информацию о правах пользователя, поэтому мы должны определить, какие маршруты в это время.
Но на тот момент маршрутизация была настроена.vue
предоставляется внутриrouter.addRoutes
Этот метод предназначен для динамической установки маршрутизации,react
Ничего про этот апи я в нём не нашёл, поэтому прошёл все роуты, чтобы его прописать, но это вызвало проблему.
к/auth
Например, я сам не имею доступа/auth
разрешения, поэтому моя боковая панель не генерирует/auth
этот список вариантов. Но мы получаем доступ к нему в адресной строке/auth
На эту страницу можно зайти (лучше вообще не генерировать этот маршрут). Так вот с этой настройкой на самом деле проблема.В данный момент я не знаю как динамически генерировать маршруты.Пока это только в根目录
Выполнить обработку разрешений
5. Загрузка по требованию
Есть также много методов загрузки по требованию.В настоящее время я пробовал только первый, потому что я также использовал импорт для реализации загрузки по требованию, когда писал Vue, поэтому я не стал заморачиваться.
1. метод импорта
//asyncComponent.js
import React from 'react'
export default loadComponent => (
class AsyncComponent extends React.Component {
state = {
Component: null,
}
async componentDidMount() {
if (this.state.Component !== null) return
try {
const {default: Component} = await loadComponent()
this.setState({ Component })
}catch (err) {
console.error('Cannot load component in <AsyncComponent />');
throw err
}
}
render() {
const { Component } = this.state
return (Component) ? <Component {...this.props} /> : null
}
}
)
// index.js
import asyncComponent from './asyncComponent.js'
const _import_ = file => asyncComponent(() => import(file))
_import_('components/Home/index.js')
Принцип прост:
- import() принимает соответствующий модуль и возвращает объект Promise
- asyncComponent получает функцию, и эта функция возвращает объект обещания.
- В функции хука componentDidMount выполните полученный метод loadComponent через async/await, получите результат, возвращенный импортом, и назначьте его для state.Component,
- Поскольку то, что мы импортируем, является компонентом React, то, что мы получаем, также является компонентом React, а затем нам нужно только отобразить компонент.
2. Связка компонент + импорт (аналогично первому ощущению)
3. react-loadable
4. bundle-loader
6. request
То, что я использую здесь, этоaxios
, использоватьaxios
сделал простой перехватчик
import axios from 'axios'
import qs from 'qs'
axios.defaults.withCredentials = true
// 发送时
axios.interceptors.request.use(config => {
// 发起请求,可以进行动画啥的
return config
}, err => {
return Promise.reject(err)
})
// 响应时
axios.interceptors.response.use(response => response, err => Promise.resolve(err.response))
// 检查状态码
function checkStatus(res) {
// 得到返回结果,结束动画啥的
if (res.status === 200 || res.status === 304) {
return res.data
}
return {
code: 0,
msg: res.data.msg || res.statusText,
data: res.statusText
}
return res
}
// 检查CODE值
function checkCode(res) {
if (res.code === 0) {
throw new Error(res.msg)
}
return res
}
export default {
get(url, params) {
if (!url) return
return axios({
method: 'get',
url: url,
params,
timeout: 30000
}).then(checkStatus).then(checkCode)
},
post(url, data) {
if (!url) return
return axios({
method: 'post',
url: url,
data: qs.stringify(data),
timeout: 30000
}).then(checkStatus).then(checkCode)
}
}
7. redux
В основном используется здесьredux-actions
создать действие,родное письмо
// action
const addTodo = text => ({
type: 'ADD_TODO',
payload: {
text,
completed: false
}
})
// reducer
const todos = (state = [], action) => {
switch(action.type) {
case 'ADD_TODO':
return [...state, action.payload]
...
default:
return state
}
}
использовалredux-actions
написание
import { createAction, handleActions } from 'redux-actions'
// action
const addTodo = createAction('ADD_TODO')
// reducer
const todos = handleActions({
ADD_TODO: (state, action) => {
return [...state, action.payload]
}
...
}, [])
// использоватьredux-actions
просто и понятно
8. connect
С редуксом эта штука в принципе незаменима,connect
В основном используется для подключения组件
а такжеredux store
, чтобы позволить компоненту получить данные в хранилище избыточности值
а также方法
connect([mapStateToProps], [mapDispatchToProps], [mergeProps],[options])
Обычно используются только первые два параметра.
-
mapStateToProps(state, ownProps)
: Получить данные указанного состояния в хранилище, а затем передать их указанному компоненту, ownProps Реквизит самого компонента -
mapDispatchToProps
: Это чтобы получить метод действия в хранилище, а затем передать указанный компонент
Применение
import toggleTodo from 'actions/todo'
const mapStateToProps = state => ({
active: state.active
})
const mapDispatchToProps = {
onTodoClick: toggleTodo
}
connect(mapStateToProps, mapDispatchToProps)(Component)
// 在Component组件中, 便能在 props 里面获取到 active 数据, 跟 onTodoClick 这个方法了
connect
В основном используется во многих местах
Так еще и упаковано
// connect.js
import actions from 'src/actions' // 所有action
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
export default connect(
state => ({state}), // 偷懒了, 每次把state里面所有的数据都返回了
dispatch => bindActionCreators(actions, dispatch) //合并所有action,并且传入dispatch, 那样我们在组件里面调用action,就不在需要dispatch了
)
Затем мы кладемconnect.js
файл черезwebpack
Атрибут псевдонима для настройки
//配置别名映射
alias: {
'src': resolve('src'),
'connect': resolve('src/utils/connect')
}
Затем мы можем обратиться к файлу следующим образом
import React from 'react'
import connect from 'connect'
@connect // 通过装饰器调用
class Component extends React.Component {
componentWillMount () {
const {state, onTodoClick} = this.props
console.log(state, onTodoClick)
}
}
Чтобы избежать проблем, я поставилstore
Все данные внутри иaction
все вернулись.
9. cssModules
существуетvue
Обычно мы устанавливаем тег стиля, устанавливаяscoped
свойства, чтобы сделать css модульным
Но когдаreact
, Я использовалcssModules
сделать модульность css
- пройти через
webpack
настраиватьcss-loader
изmodules
чтобы открыть модуляризацию css
{
loader: 'css-loader',
options: {
modules: true, //是否开启
localIdentName: '[name]__[local]___[hash:base64:5]' // 转化出来的class名字结构
}
},
- Внедрите css и добавьте className через назначение объекта
import styles from './styles.css'
export default () => (
<div className={styles.a}></div>
)
//styles.css
.a {
color: #ff4747;
}
или может пройтиreact-css-modules
для более удобного управленияclass
имя класса
import styles from './styles.css'
import CSSModules from 'react-css-modules'
class Component extends React.Component {
render () {
return (
<div styleName='a b'></div>
)
}
}
export default CSSModules(Component, styles, {
allowMultiple: true //允许多个class一起使用
})
//styles.css
.a {
color: #ff4747;
}
.b {
background: #f00;
}
Таким образом, мы можем передать строкуclass
имя класса. Примечание: не используется, когда мы добавилиclassName
, но использоватьstyleName
охватывать
10. Реализация двухсторонней привязки
class Bingding extends React.Component {
state = {
value: ''
}
handleInput = value => {
this.setState({
value
})
}
render () {
return (
<input type="text" value={this.state.value} onChange={e => {this.handleInput(e.target.value)}}/>
<div>{this.state.value}</div>
)
}
}
черезonChange
событие для запускаthis.setState
Повторный рендеринг метода рендеринга
Еще немного знаний
включать动画
,生命周期
так далее
Не так много, чтобы представить. Эти проекты в основном более или менее вовлечены.
Проблем, возникающих при разработке, довольно много, самая главная – этоreact-router
Проблема настройки, как настроить не очень.
В то же время я надеюсь, что кто-то порекомендует несколько исчерпывающих, особенно последнюю версию.react
Проект с открытым исходным кодом.
Шаги запуска проекта
- npm/yarn run dll (DllPlugin запакован, достаточно одного пакета)
- npm/yarn run dev (режим разработки)
- npm/yarn run build (рабочий режим)
резюме
Два сравнительно популярных в Китае фреймворка практически не соприкасаются друг с другом.vue
Я использовал его все время,react
Это новый контакт спустя год.
С моей нынешней точки зрения,vue
Сравниватьreact
Это действительно намного удобнее в разработке (можно использовать больше).
потому чтоvue
Многие часто используемые встроены. а такжеreact
По сути, вы должны найти соответствующий модуль самостоятельно. Он предоставляет только сам пользовательский интерфейс, а остальные в основном самодостаточны.
Основная причина в том, что вы часто находите несколько модулей, но не знаете, какой из них использовать, и вам приходится тестировать воду один за другим. Конечно,react
Сообщество сильное, так что это не большая проблема.