一直在使用vue,react快忘记了故,重新学习react项目全方位的搭建
-
安装react脚手架
npm i create-react-app -g //脚手架可以简化复杂的配置
-
创建项目
create-react-app react-demo
-
脚手架中安装react-router,react-router-dom
npm i React-Router React-Router-DOM --save
1)、React-Router-DOM:提供了 BrowserRouter, Route, Link等 API,我们可以通过 DOM 的事件控制路由。例如点击一个按钮进行跳转,大多数情况下我们是这种情况,所以在开发过程中,我们更多是使用React-Router-DOM。
2)、React-Router:提供了一些router的核心API,包括Router, Route, Switch等,但是它没有提供 DOM 操作进行跳转的API。
现在的项目结构应该是这样的
react-demo/
README.md
node_modules/
package.json
public/
index.html
favicon.ico
src/
App.css
App.js
App.test.js
index.css
index.js
logo.svg
暂时不考虑webpack的配置问题
src中index.js 相当于vue的main.js 它理应是这样的结构
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();
运用 npm run start 运行一下是否正常
下一步思考:路由如何跳转
在看了react-router与react-router-dom的区别之后,发现两者不可或缺,都安装下来,前文有安装代码
进一步思考:为了方便管理,路由是否可单独写个js,然后导入index.js
答:可以,在此看到了react的特别代码格式jsx
执行:
-
在src中建立文件夹routes并在其中建立index.jsx文件。
index.jsx内容(因为本身不熟悉react,但是接触过router类组件,对此代码可以很好的理解)import React from 'react' import { Route,Redirect } from 'react-router' import { HashRouter,Switch } from 'react-router-dom' import Home from '../App' import Cs1 from '../pages/cs1.jsx' const Routes = () => ( <HashRouter> <div> <Route exact path="/" render={()=><Redirect to="/home" />}></Route> //默认进入页面 <Switch> //声明 <Route path="/home" component={Home} /> <Route path="/cs1" component={Cs1} /> </Switch> </div> </HashRouter> ) const App = () => ( <Routes /> ) export default App
-
改变src下的index.js
//将App 的路径改为./routes/index 就成功的吧路由引入了,理所应当但又感觉到了神奇 import App from './App'; import App from './routes/index';
-
思考:既然路由配置成功了,那跳转试试?
在‘/’路径页面(这里是App.js是的不是什么html,vue)import React from 'react' import { Link } from 'react-router-dom' import logo from './logo.svg' import './App.css' function App() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <h1>首页</h1> <Link to="/cs1">测试1</Link> </header> </div> ); } export default App;
在src中新建文件夹pages并在期间创建cs1.jsx 文件为测试页面
cs1.jsx文件内容import React from 'react' import { Link } from 'react-router-dom' const cs1 = () => ( <div> <h1>这是测试1页面</h1> <Link to="/home">返回首页</Link> </div> ) export default cs1
保存后运行代码实现了基本的页面跳转功能,但是离完成一个完整的项目来说,只是冰山一角(学习到此记录20190819上午记录)
开始学习:
思考:一个项目最开始执行的一定是判断用户是否登录,猜测所用到的东西,store(新名词,redux, react-redux)
答:经过整一天的查阅学习,才稍微搞懂了router-redux与redux的用法与原理(待后期深入学习)首先将用到的包安装下来
npm install redux react-redux --S
开始redux的部分
新建文件reducer.js// 引入redux import { combineReducers } from 'redux' // 保存的值 const defaultState = { inputValue: '123', list: [1,2] } const dedState = {list:2} // 用于后面修改保存值 按需求写 function reducer(state = defaultState, action) { if( action.type === 'change_input_value') { const newState = JSON.parse(JSON.stringify(state)) newState.inputValue = action.value return newState } return state } function ress(state = dedState, action) { if (action.type === 'add_todo_item') { return Object.assign({}, state, { list: action.value }) } return state } // 抛出定义的函数 export default combineReducers({reducer,ress})
在reducer.js同级目录下新建index.js
import { createStore, applyMiddleware, compose } from 'redux' import reducers from './reducer' // 创建store const store = createStore(reducers) export default store
开始redux的部分
在最开始的src/index.js下修改部分代码import { Provider } from 'react-redux' import store from './store/index' // 运用react-redux将store带入每个路由组件中 ReactDOM.render(( <Provider store={store}> <BrowserRouter> <App /> </BrowserRouter> </Provider> ), document.getElementById('root'));
选定一个组件用于取改值,这里取App.js 这里的App 并不是上图的 App /> 不清楚请查看路由配置部分
class App extends React.Component { constructor(props) { super(props) this.state = { demo: this.props.demo // 获取store中值 } this.handleClick = this.handleClick.bind(this) } handleClick(e, name) { e.preventDefault(); const action = { type: 'add_todo_item', value: 5 } // 更改store中数据 this.props.ress(action) } render() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <h1 onClick={(e) => this.handleClick(e,this.state.demo)}>{this.props.demo.list}</h1> <Link to="/cs1">测试1</Link> <Cs /> </header> </div> ) } } // 将store内值带入props const mapStateToProps = (state, ownProps) => { return { demo: state.ress } } // 将redux的 dispatch 带入props并变更名为ress const mapDispatchToProps = (dispatch, ownProps) => { return { ress: (val) => dispatch({type: val.type,value: val.value}) } } // 重要!必须connect之后store中的数据才能插入到props中 const app = connect(mapStateToProps, mapDispatchToProps)(App); export default app;
到此,已经了解了react的路由跳转,store的数据管理,下一步应该做的就是ajax数据的获取了,相信他会比前两个轻松的多(20190820下午留)
数据交互我这里用到的是axios qs包
npm install axios
npm install qs
在/src下创建新文件夹util与api
util里创建request.js
这一部分代码习惯性原因,我直接拿了vue-elementui-admin里的axios用法,比较符合我的需求
import axios from 'axios' // 引入axios
// 创建一个axios实例
const service = axios.create({
baseURL: 'http://v.16mnc.cn:8083/neighbour_goods_admin', // url = base url + request url
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
withCredentials: true, // 当跨域请求时发送cookie
timeout: 25000 // 请求时间限制ms
})
// 请求拦截器
service.interceptors.request.use(
config => {
// 在发送请求之前做些什么
if (store.getters.token) {
// 让每个请求携带令牌
// ['X-Token'] 是一个自定义头键
// 请根据实际情况修改
// config.headers['X-Token'] = getToken()
}
return config
},
error => {
// 处理请求错误
console.log(error) // for debug
return Promise.reject(error)
}
)
// 响应拦截器
service.interceptors.response.use(
/**
* 如果您想获得http信息,例如头信息或状态信息
* 请 return response => response
*/
/**
* 通过自定义代码确定请求状态
* 这里只是一个例子
* 您还可以通过HTTP状态代码来判断状态
*/
response => {
const res = response.data
// if the custom code is not 20000, it is judged as an error.
if (res.status !== 200) {
Message({
message: res.msg || 'Error',
type: 'error',
duration: 5 * 1000
})
// 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
if (res.status === 50008 || res.status === 50012 || res.status === 50014) {
// to re-login
MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
confirmButtonText: 'Re-Login',
cancelButtonText: 'Cancel',
type: 'warning'
}).then(() => {
store.dispatch('user/resetToken').then(() => {
location.reload()
})
})
}
return Promise.reject(new Error(res.msg || 'Error'))
} else {
return res
}
},
error => {
console.log('err' + error) // for debug
Message({
message: error.msg,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
export default service
```
/api下创建user.js
```
import request from '../utils/request'
import qs from 'qs'
export function login(data) {
return request({
url: '/login/login',
method: 'post',
data: qs.stringify({
adUsername: data.username,
adPassword: data.password
})
})
}
```
在其他页面调用的时候
```html
import { login } from './api/user'
handleClick(e, name) {
e.preventDefault();
login({name: 123456,password: 123456})
.then(res => {
console.log(res)
const action = {
type: 'change_input_value',
value: {
name: res.data.name,
password: res.data.password
}
}
this.props.ress(action)
})
.catch(error =>{
console.log(error)
})
}
到这里react项目前期工作准备已经完成,有错误的地方希望大家给予指正,我也是才学习react的小歘歘O(∩_∩)O~