React-从0到1搭建一个React项目(二)

文章目录

    • react路由
      • 路由配置
    • 数据层
      • 定义action
      • 实现reduce
      • 创建store
      • 使用 Provider
    • 容器层
      • 实现一个组件
      • 组件CSS
      • 如何调用reduce中的方法和使用store中的数据
    • Demo

本篇是《从0到1搭建react项目》的第二篇,主要介绍react路由配置、数据层和容器层实现。
相关文章:React-从0到1搭建一个React项目(一)

react路由

react-router基本已成为react路由的标准解决方案。我使用的是react-router-dom。
react-router包含了所有react-router-dom和react-router-native的公共组件,实现了路由的核心功能。通常情况下,如果是开发web应用,使用react-router-dom就能满足需求。如果是用react-native开发,就用react-router-native。
具体的一些介绍,可以参考:

  1. https://github.com/ReactTraining/react-router/issues/4648
  2. https://stackoverflow.com/questions/42684809/react-router-vs-react-router-dom-when-to-use-one-or-the-other

路由配置

路由的使用可以参考官方文档。也可以按下面的步骤来:

  1. 在项目src目录下新建一个routes.js文件,用来管理所有的路由。这里import了App组件,如果后续还有别的组件,import进来,增加一条Route即可
import React from 'react'
import { BrowserRouter as Router, Route } from "react-router-dom";
import App from './App'

const AppRouter = () => (
  
    
); export default AppRouter;
  1. index.js文件中引入AppRouter
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import * as serviceWorker from './serviceWorker';
import AppRouter from './routes'

ReactDOM.render(, document.getElementById('root'));

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

到这里,实现了一个简单的路由功能。接下来实现数据层。

数据层

React Redux可以让react组件从redux store中读取数据,并且通过dispatch action更新store中的数据。详细使用可查看官方文档。
我们的数据层就是使用react-redux来管理整个应用的状态。
React Redux提供了组件,可以让web应用的所有组件都能操作redux store。组件接收一个store作为参数,而创建store前,需要先定义好action和reduce。下面先来看下action的定义。

定义action

  1. /src/actions/目录下新建actions.js文件,如果项目的action比较多,可以拆分成多个action.js文件。
  2. 定义action名称和方法。假设要实现的action是一个保存用户信息的操作。可以定义如下:
export const SAVE_USER_INFO = "SAVE_USER_INFO"
export const saveUserInfo = (userInfo) => ({
	type: SAVE_USER_INFO,
	userInfo
})

这里定义了一个type常量SAVE_USER_INFO,用来标识action的类型;定义了一个方法saveUserInfo,接收userInfo参数,用来更新store中的用户信息。
定义好action之后,就可以实现reduce了。

实现reduce

  1. /src/reduce目录下新建两个文件index.jshome-reduce.js,其中index.js里通过redux的combineReducers把各个业务模块的reduce组合成一个reduce,home-reduce.js里面是业务模块的reduce,这里就是实现一个保存用户信息的操作。代码如下:
//index.js
import { combineReducers } from 'redux'
import home from './home-reduce'

export default combineReducers({
  home
})
//home-reduce.js
import { SAVE_USER_INFO } from '../actions/actions'

const initialState = {
  userInfo: null

}

const home = (state = initialState, action) => {
  switch (action.type) {
  case SAVE_USER_INFO:
    return Object.assign({}, state, {
      userInfo: action.userInfo
    })
  default:
    return state
  }
}

export default home

创建store

查看官方步骤

  1. 在/src/configureStore目录下,新建configureStore.js文件,内容:
import { applyMiddleware, createStore } from 'redux'
import thunkMiddleware from 'redux-thunk'
import { createLogger } from 'redux-logger'
import { composeWithDevTools } from 'redux-devtools-extension'
import rootReducer from '../reducers'

export default function configureStore(preloadedState) {
  const middlewares = [thunkMiddleware]
  if (process.env.NODE_ENV !== 'production') {
      middlewares.push(createLogger())
  }

  const middlewareEnhancer = applyMiddleware(...middlewares)

  const enhancers = [middlewareEnhancer]
  const composedEnhancers = composeWithDevTools(...enhancers)

  const store = createStore(rootReducer, preloadedState, composedEnhancers)

  //reducer hot loading 
  if (process.env.NODE_ENV !== 'production' && module.hot) {
    module.hot.accept('../reducers', () => store.replaceReducer(rootReducer))
  }

  return store
}

这里面核心的代码就是const store = createStore(rootReducer, preloadedState, composedEnhancers)。createStore传递了三个参数,第一个参数是reduce,提供了更新state的实现。preloadedState是预加载的state,服务端渲染时会用到。composedEnhancers中集成了多个Middleware,你可以利用 Redux middleware 来进行日志记录、创建崩溃报告、调用异步接口或者路由等等。

使用 Provider

在根组件上使用,修改src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import AppRouter from './routes';
import configureStore from '../../configureStore/configureStore';
import './index.css';

const store = configureStore()

ReactDOM.render(
  
  	
  ,
  document.getElementById('root'))

到这里数据层就算完成了,接下来看下怎么在容器层调用保存用户信息的方法以及如何使用store里面的数据。

容器层

实现一个组件

/src/container目录下新建一个容器组件home.js。代码为:

import React from 'react'
import styled from 'styled-components'
import PropTypes from 'prop-types'
import { saveUserInfo } from '../actions/actions'
import { connect } from 'react-redux'
import Input from '@material-ui/core/Input';

const Container = styled.div`
  display: flex;
  height:100%;
  width:100%;
  flex-direction:column;
  align-items:center;
  background-color:#F0F0F0;
`
const NameFromStore = styled.div`
	font-size:large;
`

class Home extends React.Component {
	constructor(props) {
		super(props)
		this.handleChange = this.handleChange.bind(this)
	}

	handleChange(event) {
		var userInfo = {
			name: event.target.value
		}
		this.props.saveUserInfo(userInfo)
	}

	render() {
		return (
			
			
			
				{this.props.userInfo && this.props.userInfo.name}
			
			
		);
	}

}

const mapStateToProps = state => ({
  userInfo: state.home.userInfo
})

const mapDispatchToProps = dispatch => {
  return {
    saveUserInfo: (userInfo) => (
    dispatch(saveUserInfo(userInfo))
    )
  }
}

Home.propTypes = {
  saveUserInfo: PropTypes.func,
}

export default connect(mapStateToProps, mapDispatchToProps)(Home)

home.js组件实现的功能:定义了一个input输入框,将输入的信息保存到store中,再从store中取出保存的信息展示出来。

组件CSS

home.js中使用了styled-components,它可以让我们在组件的js文件中直接编写css代码。传统的在css文件中编写样式的方法存在诸多弊病,比如定义的class-name是全局的,很容易导致样式覆盖。styled-components是一个现代的解决方案,同时还提供了主题设置,方便应用样式的统一。感兴趣的可以查看官网。

如何调用reduce中的方法和使用store中的数据

正如第一篇文章的架构图中画的一样,容器层的组件和数据层reduce的交互是通过定义的action作为桥梁的。在容器层的home.js中,把actions.js中定义的更新store的方法import进来,然后定义了一个mapStateToProps方法和mapDispatchToProps,分别定义了store中的state到组件的props映射和dispatch方法到组件props方法的映射,再通过connect将两种映射和组件关联起来。

import { saveUserInfo } from '../actions/actions'
...

//将store中的state数据映射到组件的props属性
const mapStateToProps = state => ({
  userInfo: state.home.userInfo
})

//将组件的saveUserInfo属性映射到dispatch()方法,从而通过action调用到reduce中定义的方法更新store
const mapDispatchToProps = dispatch => {
  return {
    saveUserInfo: (userInfo) => (
    dispatch(saveUserInfo(userInfo))
    )
  }
}

Home.propTypes = {
  saveUserInfo: PropTypes.func//定义Home的props属性
}
export default connect(mapStateToProps, mapDispatchToProps)(Home)

我们修改routes.js的代码,将Home组件作为第一个渲染的组件,看下效果


import React from 'react'
import { BrowserRouter as Router, Route } from "react-router-dom";
import Home from './container/home'

const AppRouter = () => (
  
    
); export default AppRouter;

效果图:
React-从0到1搭建一个React项目(二)_第1张图片
到这里,我们项目的架子基本上搭建完成了,剩下的只要根据自己的业务划分不同的模块,分别放入相应的数据层、容器层和组件层。
接下来的文章会分享一下react项目中如何解决自定义环境变量、开发测试生产打包以及多页面(html)的问题。

Demo

附上Demo的github地址:https://github.com/miguoer/react-sample

你可能感兴趣的:(React)