react全家桶实战

整个目录结构如下:
react全家桶实战_第1张图片

package.json代码如下:

{
  "name": "active",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "react": "^16.4.1",
    "react-dom": "^16.4.1",
    "react-redux": "^5.0.7",
    "react-router-dom": "^4.3.1",
    "react-scripts": "1.1.4",
    "react-swipe": "^5.1.1",
    "react-transition-group": "^2.3.1",
    "redux": "^4.0.0",
    "redux-logger": "^3.0.6",
    "redux-promise": "^0.6.0",
    "redux-thunk": "^2.3.0",
    "swipe-js-iso": "^2.0.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  },
  "proxy": {
    "/api": {
      "target": "http://localhost:1000/",
      "changeOrigin": true,
      "pathRewrite": {
        "/api": "/"
      }
    }
  },
  "devDependencies": {
    "babel-plugin-transform-decorators-legacy": "^1.3.5"
  }
}

api/home.js(在redux中的action中被引入store/actions/home.js)用来获取首页数据

//获取轮播图数据
function getSilders() {
    //最原始的fetch
    // fetch('api/loop', {method: "post"}).then(function (response) {
    //     // 转换为 JSON
    //     console.log("response")
    //     console.log(response)
    //     return response.json();
    // }).then(function (j) {
    //     console.log('获取到的数据是====');
    //     console.log(j);
    //     return j
    // });
    ////redux-promise的用法:可以将payload中的promise执行,执行后将内容放到action.payload中进行派发:{ type:SET_SLIDERS, patload:[{},{},{},{}] }
    return fetch('api/loop', {method: "post"})
}
export { getSilders }

common/Tab/Tab.js;在app.js中被引入;作为底部导航;切换主页面

import React,{Component} from 'react'
import {Link,NavLink} from 'react-router-dom'

export default class Tab extends Component{
    constructor(){
        super()

    }
    render(){
        return (
            <ul>
                <li><Link to={'/'}> 首页Link>li>
                <li><Link to={'/lesson'} >课程 Link>li>
                <li><Link to={'/profile'} > 用户中心Link>li>

                {/*第二种写法如下:*/}
                {/*<li> <NavLink to={'/'}>首页NavLink> li>*/}
                {/*<li> <NavLink to={'/lesson'}>课程NavLink> li>*/}
                {/*<li> <NavLink to={'/profile'}>用户中心NavLink> li>*/}
            ul>
        )
    }
}

总结:
1:路由的2种写法NavLink , Link:
2:在当前路由下,再次点击路由切换报警告如下:
react全家桶实战_第2张图片

containers/Home/Homeheader/Homeheader.js;被Home.js被引入

import React, {Component} from 'react'
import logo from '../../../common/img/logo.png'
import './index.css'
import Transition from 'react-transition-group/Transition';

const duration = 10;
//默认样式
const defaultStyle = {
    transition: `opacity ${duration}ms ease-in-out`,
    opacity: 0,
    display:'none'
}

const transitionStyles = {
    entering: {opacity: 0},
    entered: {opacity: 1},
};

export default class Homeheader extends Component {
    constructor() {
        super()
        this.state = {
            isShow: false
        }
    }

    changeShow = () => {
        this.setState({
            isShow: !this.state.isShow
        })
    }
    selectLesson=(e)=>{
        //li元素,当前点击的元素是谁就是谁
        // console.log(e.target)
        // //整个ul元素。事件在谁身上绑着就是谁
        // console.log(e.currentTarget)
        // //获取h5 data属性
        // console.log(e.target.dataset.type)
        //隐藏元素
        this.changeShow()
        this.props.selectCurrentLesson(e.target.dataset.type)
    }

    render() {
        return (
            
'home-header'}>

this.changeShow} className={'iconfont icon-menu menu'}> 'logo'} src={logo} alt=""/>

in={this.state.isShow} timeout={duration} onEnter={(node)=>{ node.style.display='block' }} onExited={(node)=>{ node.style.display='none' }}> {(state) => (
    'menu-ul'} style={{ ...defaultStyle, ...transitionStyles[state] }} onClick={(e)=>{ this.selectLesson(e) }} >
  • "all">全部课程
  • "react">react课程
  • "vue">vue课程
)}
) } }

总结:
1:显示隐藏采用‘react-transition-group’组件
2:官方组件地址:https://github.com/reactjs/react-transition-group
3:html5中的data属性获取:e.target.dataset.type
4:效果图如下:
react全家桶实战_第3张图片

containers/Home/Home.js;路由‘/’的组件

import React, {Component} from 'react'
import './index.css'
import Homeheader from './Homeheader/Homeheader'
import {connect} from 'react-redux'
import HomeSlider from './HomeSlider'
import Loading from '../../components/Loading'
import actions from '../../store/actions/home'
//修饰符的用法待研究
@connect(state => ({...state.home}), actions)
export default class Home extends Component {
    // constructor(){
    //     super()
    // }
    componentWillMount() {
        // 第一种方法:直接ajax
        // fetch('api/loop', {method: "post"}).then(function (response) {
        //     // 转换为 JSON
        //     return response.json();
        // }).then(function (j) {
        //     console.log(j);
        // });
        // 第2种方法:ajax从外部引入
        // getSilders()
        // 第3种方法:采用redux;只有connect装饰器以后才能使用redux中的store;如果redux中存在数据;则不进行请求
        if (this.props.slider.length === 0) {
            this.props.getSliderApi()
        }

    }
    selectCurrentLesson = (val) => {
        // console.log('传给父组件的值是'+val)
        console.log(this.props)
        this.props.updateCurrentLesson(val)
    }
    render() {
        return (
            
this.selectCurrentLesson}> //解决轮播图不出现的BUG { this.props.slider.length>0 ? this.props.slider}> : }
) } }

containers/Lesson/Lesson.js;路由‘/lesson’的组件

import React,{Component} from 'react'
import './index.less'

export default class Lesson extends Component{
    // constructor(){
    //     super()
    // }
    render(){
        return (
            <div>
            Lesson
            div>
        )
    }
}

containers/Profile/Profile.js;路由‘/Profile’的组件

import React,{Component} from 'react'
import './index.less'

export default class Profile extends Component{
    // constructor(){
    //     super()
    // }
    render(){
        return (
            <div>
            Profile
            div>
        )
    }
}

store/actions/home.js;在Home.js中被引入;

import * as Types from '../action-types'
import { getSilders } from '../../api/home'


let actions={
    //更新当前选择的课程
    updateCurrentLesson(lesson){
        return {
            type:Types.SET_CURRENT_LESSON,
            lesson
        }
    },
    getSliderApi(){
        // redux-thunk
        return function (dispatch,getState) {
            //redux-promise的用法:可以将payload中的promise执行,执行后将内容放到action.payload中进行派发:{ type:SET_SLIDERS, patload:[{},{},{},{}] }
            dispatch({type:Types.SET_SLIDERS ,payload:getSilders().then(function (response) {
                    // 转换为 JSON
                    console.log("response")
                    console.log(response)
                    if(response.status==200){
                        return response.json();
                    }else{
                        alert('服务器挂掉了')
                    }
                }).then(function (j) {
                    // console.log('获取到的数据是====');
                    // console.log(j);
                    return j
                })})
        }

    }
}
export default  actions

store/reducers/home.js;在下面的index.js中被引入;

//一个页面一个reducer
import * as Types from '../action-types'
let initState={
    currentLesson:'all',
    slider:[]
}
function home(state=initState, action) {
    switch (action.type){
        case Types.SET_CURRENT_LESSON:
            return {
                ...state,
                currentLesson:action.lesson
            }
        case Types.SET_SLIDERS:
            return {
                ...state,
                slider:action.payload
            }
        default:{
            return state
        }


    }
}
export default home

store/reducers/index.js;在store中index.js中被引入;

import { combineReducers } from 'redux'
import home from './home'
export default  combineReducers({
    home
})

store/action-types.js;在store中的各种JS文件中引入;

//设置当前课程
export const SET_CURRENT_LESSON='set_current_lesson'
//设置轮播图数据
export const SET_SLIDERS='set_sliders'

store/index.js;被最外层的index.js引入

import { createStore , applyMiddleware } from 'redux'
import reduxLogger from 'redux-logger'
import reduxThunk from 'redux-thunk'
import reduxPromise from 'redux-promise'
import reducer from './reducers/index'


let store= createStore(reducer,applyMiddleware(reduxLogger,reduxThunk,reduxPromise))
window._store=store; //为了测试用
export default store

总结:
写redux的逻辑
1:action-types
2:reducer
3:action
4:组件中调用action; dispatch
react全家桶实战_第4张图片

架构最外层的index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
//配置路由组件
import {HashRouter as Router,Route, Switch} from 'react-router-dom'
import Home from './containers/Home/Home'
import Profile from './containers/Profile/Profile'
import Lesson from './containers/Lesson/Lesson'

import {Provider} from 'react-redux'
import store from './store/index'

import './common/reset.css'

ReactDOM.render(
    
        
            
                
                    '/' exact={true} component={Home}>
                    '/lesson' component={Lesson}>
                    '/profile'} component={Profile}>
                
            
        
    
    , document.getElementById('root'));
registerServiceWorker();

架构最外层的app.js

import React, { Component } from 'react';
import Tab from './common/Tab/Tab'


class App extends Component {
  render() {
    return (
        <div>
            {this.props.children}
            
        div>

      // 
// {this.props.children} // //
); } } export default App;

HomeSlider.js

import React,{Component} from 'react'
//轮播图组件
import ReactSwipe from 'react-swipe';
export default class HomeSlider extends Component{
    constructor(){
        super()
        this.state={
            index:0
        }
    }

    render(){
        let _this=this
        let opts={continuous: true,
            speed: 400,
            auto: 1000,
            callback: function(index, elem) {
                _this.setState({
                    index:index
                })
            },
        }
        return (
            <div className={'loop'}>
                "carousel" swipeOptions={opts}>
                    {
                        this.props.lists.map((item, index) => {
                            return (
                                <div key={index}><span""/>div>
                            )

                        })
                    }
                
                <div className={'slider-dots'}>
                    {
                        this.props.lists.map((item, index) => {
                            return (
                                index} className={this.state.index===index ? 'active': ''}>
                            )

                        })
                    }

                div>
            div>

        )
    }
}

1:轮播图插件

npm install react swipe-js-iso react-swipe

轮播图插件swipe-js-iso拖动一次后不再轮播的BUG修复
react全家桶实战_第5张图片

 delay = options.auto || 0;

你可能感兴趣的:(react全家桶)