react项目成型的个人心得

此文是我在react项目搭建后对整个流程的一些环节进行整理和梳理,如有错误还请指正。

一般目录结构搭建好后,我们会首先在src中开始工作,因为大多数代码都是在src中完成的。
这里要说一个React项目的构建思想:

1 准备工作
快速构建React项目,我采用的是脚手架构建方式。
首先我们需要复制一个脚手架。将里面public、src文件夹下的文件全部删除。接着将需要的html粘进public文件夹下,当然也包括对应的css。
接下来就需要在src文件夹下建立一个index.js文件,用来将js文件中的信息传递到html里面;同时建立一个components文件夹,用来存放react组件;
index.js文件里面引入react和react-dom库,并引入主组件APP.js。将其传递到id为app的div标签里面。

比较全面的目录结构如下:

  • public

  • src
    –api (一些公用方法,如ajax请求函数的定义)
    –assets (公用的图片和less文件)
    –components (UI组件)
    –containers (容器组件,用于包装UI组件来传递方法和redux状态)
    –redux (actions,action-types,reducers,store)

  • src下的index.js,是整个项目的入口文件。核心是用来将各个容器组件包装的UI组件以路由组件的形式渲染到真实DOM app中。

关于入口文件以下是基础和全面版:
react项目成型的个人心得_第1张图片

ReactDOM.render((
  
    
      
        
        
        {/*不写path,默认匹配所有路径*/}
        
      
    
  
), document.getElementById('app'));

2 建立主组件
其实就是在src内写UI组件,根据不同的功能,将整个html里面的标签需要设计拆分成组件。
首先我们新建app.js文件。其实后面每个组件的套路都是一样的;通用代码如下。
const React,{Component} from “react”;
Class App extends Component{
render()
return(
这里面放html代码;
)
}
export default app;
基本上就是这样套路。上来就这么写就ok,不用多想。

3拆分组件

这时需要分析怎么拆分。根据功能点拆分,这个是最基本的。拆分完要细化拆分,功能里面有独立功能的拆分,有多条同样数据的拆分。比如一个ul下多个li的直接拆分。然后根据上面的套路建立对应的js文件夹。
完成后在App.js文件夹里面引入每个对应的组件,起初可以使用标签的方式进行添加,保证组件可以正常加载。到了后来都用路由组件包装一下。可以参考上文的入口文件的书写方式。

4.动态化修改
这一步骤是非常关键的,直接决定做好的功能是否可用。首先将静态的数据提取出来,需要保存的在本页面的state中保存好,如果有多个页面需要使用的数据或者交互的数据,这时就要引用redux,集中管理公用的状态。

下面我们引入一个业务场景,加入注册页面需要向服务器发送ajax请求。下面是围绕着redux的一套比较固定的逻辑。

1.定义接口和方法
因为要发送ajax请求,首先在api中定义好axios方法和针对于不同业务的请求函数。
注意:此处prefix为空,因为在开发环境中解决跨域问题可以使用proxy方法。

//定义注册的请求
export const reqRegister = data => ajax(`${prefix}/register`, data, 'POST');

2.完成store

import {createStore, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import {composeWithDevTools} from 'redux-devtools-extension';
//引入reducers函数
import reducers from './reducers';

export default createStore(reducers, composeWithDevTools(applyMiddleware(thunk)));

3.actions和action-type
actions内部是创建action对象的工厂函数,actions内会定义一些同步函数,为了方便存储和reducers复用会存储到actions-types中。当涉及到异步函数时,我们会首先定义一个同步函数,然后在异步函数内调用同步函数。由于发送ajax请求是异步函数,所以采用如下写法。

//定义同步action creator
export const authSuccess = data => ({type: AUTH_SUCCESS, data});
export const authError = data => ({type: AUTH_ERROR, data});

需要定义两个同步方法,因为注册存在成功和失败两种情况,返回值不相同。

//定义异步action creator
export const register = ({username, password, rePassword, type}) => {
  //表单验证
  if (!username) {
    //变成同步action creator
    return authError({errMsg: '请输入用户名'});
  } else if (!password) {
    return authError({errMsg: '请输入密码'});
  } else if (password !== rePassword) {
    return authError({errMsg: '两次密码输入不一致'});
  }
  
  return dispatch => {
    //做异步任务,发送ajax请求
    reqRegister({username, password, type})
      .then(({data}) => {
        //请求成功~
        if (data.code === 0) {
          //注册成功~
          //更新状态, 分发成功的action对象
          dispatch(authSuccess(data.data));
        } else {
          //注册失败,更新状态,分发失败的action对象
          dispatch(authError({errMsg: data.msg}));
        }
      })
      .catch(err => {
        //请求失败~
        dispatch(authError({errMsg: '网络不稳定,请刷新试试~'}));
      })
  }
}

4.reducers
这里是真正更新store中状态的地方。这里定义了公用状态的初始化值和更新状态的方法。定义 方法时需要传两个参数,一个是previousState,另一个是action,通过对action.type的判断,就知道ajax请求失败了还是成功了,从而通过return不同的值来控制store中状态的不同。

//初始化状态的值
const initUserState = {
  username: '',
  type: '',
  _id: '',
  errMsg: '',
  redirectTo: '',
  header: '',
  post: '',
  salary: '',
  info: '',
  company: ''
};
function user(previousState = initUserState, action) {
  switch (action.type) {
    case AUTH_SUCCESS :
      return {...action.data, redirectTo: getRedirectPath(action.data.type, action.data.header)};
    case AUTH_ERROR :
      return {...initUserState, ...action.data};
    case UPDATE_USER_INFO :
      return {...action.data, redirectTo: getRedirectPath(action.data.type, action.data.header)};
    case RESET_USER_INFO :
      return {...initUserState, ...action.data}
    default :
      return previousState;
  }
}

当有多个函数时,可以使用合并reducers函数的方式

//默认暴露合并后的reducers函数
// {xxx: function xxx() {}, yyy: function yyy() {}}
export default combineReducers({
  user,
  userList,
  chatMessages
})

至此“redux无脑一顿操作’’ 完成了请求方法的定义。现在只需要在注册页面中调用就好了,可是现在问题来了,这个方法怎么从actions传过去。
此处就用到了容器组件

import {connect} from 'react-redux';
//引入UI组件
import Register from '../components/register';
//引入action creators
import {register} from '../redux/actions';
//暴露容器组件
export default connect(
  state => ({user: state.user}),
  {register}
)(Register);

然后在组件中以props的方式拿到传递过来的redux状态和方法,就可以调用ajax请求如下。

register = async () => {
    //收集表单数据
    const {laoban, password, rePassword, username} = this.state;
    //发送ajax
    console.log(laoban, password, rePassword, username);
    //调用容器组件传递的更新状态的方法
    this.props.register({type: laoban ? 'laoban' : 'dashen', password, rePassword, username});
  }

至此,一个react项目中比较简单的业务逻辑基本完成。整个项目中会出现各种问题和更优的写法,所以此套逻辑适用于一般业务逻辑场景,具体问题需要接待对待。

(想要看整个项目逻辑的可以看一下我的仓库,关于在线招聘的react项目。
https://github.com/tunshiyu/zhipin-client)

你可能感兴趣的:(react,redux,项目流程)