Novice-level configuration react react-router4.0 redux fetch sass


foreword

Recently, the company has come to a few interns, and I happen to have nothing important at hand, and then the leader asked me to take them to learn react and lay the foundation for the next react project.
Then I wrote a few demos at random to help them understand how a serious project builds a configuration project.
Share it now, I hope it can help those in need. Although some directories in this demo are useless, I still list them out in order to show the directory skeleton structure of a regular project.
I have not classified the create-react-app template files. After understanding, you can classify them yourself and add a style folder.

text

As far as the current environment is concerned, when developing react or vue projects, there should be few people who drink react library files directly in html, and they all use the front-end construction tool webpack + es6 to write projects. Therefore, I directly recommend the scaffolding create-react-app officially produced by facebook to do the project. create-react-app is the most suitable scaffolding for beginners to learn to use, all are simple commands. There is no need to clone the entire project first, and then install the dependencies like other scaffolding.

The first step (install the tool, generate the project, start the project)

Install the create-react-app tool

npm install -g create-react-app    

build project

create-react-app react-demo

After the project is generated, all dependencies will be downloaded automatically.
After entering the project, start the project

cd react-demo
npm start 或者 yarn start

Both npm and yarn are package managers, and both can download dependencies. The details are not explained here. You can search for details by yourself. A project is best to use a package management tool, do not mix, use yarn to download dependencies below. Do not do otherwise .

After the project starts, open port 3000.
The project started successfully as shown below:


The second step (configure react-router4.0, including routing parameters, etc.)

1. Install dependencies

yarn add react-router-dom --save

2. Create a new file and configure routing
srcCreate a new directory in the containersdirectory Place the main page file in
srcthe directory Create a new directory in the componentsdirectory Place a high-reuse template file
in containersthe directory Create a new one inHome.js

Home.js code

import React, { Component } from 'react';
class Home extends Component {
    render() {
        return (
            <div>
                Home
            </div>
        );
    }
}

export default Home;

containersNew inList.js

List.js code

import React, { Component } from 'react';
class List extends Component {
    render() {
        return (
            <div>
                List
            </div>
        );
    }
}

export default List; 

containersNew inMine.js

Mine.js code (secondary routing, routing parameter example)

import React, {Component} from 'react';
import {BrowserRouter as Router, Route, Link} from 'react-router-dom';
import Mine1 from './Mine1'
import Mine2 from './Mine2'

class Mine extends Component {
    constructor(props) {
        super(props);
        this.state = {
            param: ''
        };
    }
    changeParam(event) {
        this.setState({
            param: event.target.value
        })
    }
    render() {
        return (
            <Router>
                <div>
                    Mine
                    传参示例:<input type="text" placeholder='请输入要传递到mine2的参数' value={this.state.param} onChange={this.changeParam.bind(this)}/>
                    <div className="mine-nav">
                        {/*编写导航*/}
                        <ul>
                            <li><Link to={`${this.props.match.url}/mine1`}>Mine1</Link></li>
                            <li><Link to={`${this.props.match.url}/mine2/${this.state.param? this.state.param : "default-param"}`}>Mine2</Link></li>
                            {/*传参示例,如果没有参数,传默认参数*/}
                        </ul>
                        {/*路由匹配*/}
                        <div>
                            <Route exact path={`${this.props.match.url}/mine1`} component={Mine1}/>
                            <Route path={`${this.props.match.url}/mine2/:param`} component={Mine2}/>
                        </div>
                    </div>
                </div>
            </Router>
        );
    }
}

export default Mine;

containersNew inMine1.js

Mine1.js code

import React, { Component } from 'react';
class Mine1 extends Component {
    render() {
        return (
            <div>
                Mine1
            </div>
        );
    }
}

export default Mine1; 

containersNew inMine2.js

Mine2.js code (example of routing parameters)

import React, { Component } from 'react';
class Mine2 extends Component {
    render() {
        return (
            <div>
                2222222222222 传递的参数:{this.props.match.params.param}
            </div>
        );
    }
}

export default Mine2;

Modify the entry App.js file as follows:

import React, { Component } from 'react';
import {BrowserRouter as Router, Route, Link} from 'react-router-dom';
import List from './containers/List.js'
import Home from './containers/Home.js'
import Mine from './containers/Mine.js'
import './App.css'
import logo from './logo.svg'

class App extends Component {
    render() {
        return (
            <div className="App">
                <div className="App-header">
                    <img src={logo} className="App-logo" alt="logo" />
                    <h2 className='App-title'>Welcome to React Plan</h2>
                </div>
                <div className="App-content">
                    {/*路由配置*/}
                    <Router>
                        <div className="content-box">
                            {/*编写导航*/}
                            <ul className="nav">
                                <li><Link to="/">首页</Link></li>
                                <li><Link to="/list">列表页</Link></li>
                                <li><Link to="/mine/mine1">我的页面二级路由</Link></li>
                                {/*link指向二级路由的默认页面*/}
                            </ul>
                            {/*路由匹配*/}
                            <div className="content">
                                <Route exact path="/" component={Home}/>
                                <Route path="/list" component={List}/>
                                <Route path="/mine" component={Mine}/>
                            </div>
                        </div>
                    </Router>
                </div>
            </div>
        );
    }
}

export default App

Modify the App.css file for a little more styling:

.App {
    text-align: center;
}
.App-logo {
    animation: App-logo-spin infinite 20s linear;
    height: 80px;
}
.App-header {
    background-color: #222;
    height: 150px;
    padding: 20px;
    color: white;
}
.App-title {
    font-size: 1.5em;
}
.App-intro {
    font-size: large;
}
@keyframes App-logo-spin {
    from {
        transform: rotate(0deg);
    }
    to {
        transform: rotate(360deg);
    }
}

/*下面是新添加的样式*/
* {
    margin: 0;
    padding: 0;
    list-style: none;
}
.content-box{
    overflow: hidden;
}
.nav {
    padding: 20px;
    float: left;
    width: 160px;
    background-color: #fcc;
}
.nav li{
    line-height: 30px;
}
.content{
    padding: 20px 0 0 200px;
    background-color: #ccf;
    height: 110px;
}
.mine-nav{
    background-color: #cfc;
    margin-top: 20px;
    height: 70px;
}
.mine-nav ul{
    overflow: hidden;
}
.mine-nav ul li{
    float: left;
    width: 50%;
}
.mine-nav>div{
    margin-top: 20px;
}

You're done, just give it a try. After the configuration is complete, the page is as follows:

The third step (configure redux)

What is redux specifically, I won't mention it here. If you want to know more about it, it is best to read the blog of Mr. Ruan Yifeng. Redux introductory tutorial to understand what redux is, or whether your project needs redux or not. Here is only how to configure redux.
1. Install dependencies

yarn add redux react-redux --save

2. Create a new file, configure
srcthe new storedirectory place the store configuration file
srcin the directory, create a new reducersdirectory in the directory, place regular files in
srcthe directory, create a new constantsdirectory , place data in
srcthe directory, create a new actionsdirectory in the directory, and place the trigger update file
in storethe new directory.configStore.js

store > configStore.js file

import { createStore } from 'redux'
//引入规则文件
import rootReducer from '../reducers/index.js'
export default function configStore(initState){
        // 创建store
        const store = createStore(
            rootReducer,
            initState,
            // 如果安装了redux插件可按照版本打开下面的注释
            // window.devToolsExtension ? window.devToolsExtension() : undefined
            // window.__REDUX_DEVTOOLS_EXTENSION__ ? window.__REDUX_DEVTOOLS_EXTENSION__() : undefined
        )
        return store
}

reducersNew in New inindex.js
New inreducersnumber.js

reducers > index.js file

// 规则性文件
import { combineReducers } from 'redux'
import number from './number'
// 如果有多个规则,则引入多个文件
//import XXXX from './XXXX'

// 创建规则
export default combineReducers({
    // XXXX,
    number
})

reducers > number.js file

import * as actionTypes from '../constants/number.js'
import { combineReducers } from 'redux'

const text =  function (state = actionTypes.TEXT, action){
    switch(action.type) {
        case actionTypes.TEXT :
            return action.data.text
        default:
            return state
    }
}

const count =  function (state = actionTypes.COUNT, action){
    switch(action.type) {
        case actionTypes.COUNT :
            return action.data.count
        default:
            return state
    }
}

export default combineReducers({
    text,
    count
})

constantsNew innumber.js

constants > number.js file

export const COUNT = 100;
export const TEXT = 'number大类下的数据';

containersIn the modification Home.js(slightly changed the home component to use redux)

containers > Home.js file

import React, { Component } from 'react';
import {connect} from 'react-redux';
class Home extends Component {
    render() {
        return (
            <div>
                Home <br/>
                {this.props.text} ==> {this.props.count}
            </div>
        );
    }
}

// 如果只是读取数据,那么只需要这一个方法即可。(这里两个写出来只是为了方便理解)
function mapStateToProps(state){
    return {
        count: state.number.count,
        text: state.number.text
    }
}
// 同理,如果只是设置数据,那么只需要这一个方法即可。
function mapDispatchToProps(dispatch) {
    return {

    }
}
export default connect(
    mapStateToProps,
    mapDispatchToProps
)(Home)

At this point, the first step should have been achieved, and the data can be read. As shown in the figure:

The read data is realized, and the setting data must be realized next.

containersNew inTestRedux.js

containers > TestRedux.js file

import React, { Component } from 'react';
import {bindActionCreators} from 'redux'
import {connect} from 'react-redux'
import * as handlerNumberActions from '../actions/number.js'

class TestRedux extends Component {
    textChange(event){
        this.props.handlerNumberActions.changeText({
            text: event.target.value
        })
    }
    numberAdd(){
        this.props.handlerNumberActions.addNumber({
            count: this.props.count
        })
    }
    numberSubtract(){
        this.props.handlerNumberActions.subtractNumber({
            count: this.props.count
        })
    }
    
    
    render() {
        return (
            <div style={{height:'100px',background: '#ffc',padding: '10px'}}>
                <ul>
                    <li>修改redux数据</li>
                    <li>修改文本: <input type="text" style={{padding: '5px 10px'}} value={this.props.text} onChange={this.textChange.bind(this)} /></li>
                    <li>操作数值:
                        <button style={{padding: '5px 10px'}} onClick={this.numberAdd.bind(this)}>+</button>
                        -------------------
                        <button style={{padding: '5px 10px'}} onClick={this.numberSubtract.bind(this)}>-</button>
                    </li>
                </ul>
            </div>
        );
    }
}

function mapStateToProps(state){
    return {
        count: state.number.count,
        text: state.number.text
    }
}
function mapDispatchToProps(dispatch) {
    return {
        handlerNumberActions: bindActionCreators(handlerNumberActions, dispatch)
    }
}
export default connect(
    mapStateToProps,
    mapDispatchToProps
)(TestRedux)

actionsNew innumber.js

actions > number.js file

import * as actionTypes from '../constants/number.js'

export function addNumber(data){
    data.count ++;
    return {
        type: actionTypes.COUNT,
        data
    }
}
export function subtractNumber(data){
    data.count --;
    return {
        type: actionTypes.COUNT,
        data
    }
}

export function changeText(data){
    return {
        type: actionTypes.TEXT,
        data
    }
}

At this point, the complete redux is completely configured. Click a little, or try changing the text.
The directory structure and effect are as follows:


Step 4 (Configure fetch)

what is fetch? Fetch is actually a substitute for XMLHttpRequest. Compared with the rough things like XMLHttpRequest, fetch obviously looks more refined. The best thing is that fetch is based on Promise, which frees us from the nightmare of callback hell. Let's simply encapsulate fetch. Easy to use in react.
1. Install dependencies

yarn add whatwg-fetch es6-promise --save

2. Create a new file to encapsulate the fetch method

srcCreate a new directory under the directory, create a new package fetch under fetchthe fetchfileindex.js

fetch > index.js file

import 'whatwg-fetch'
import 'es6-promise'

export function get(url) {
    let result = fetch(url, {
        credentials: 'include',
        headers: {
            'Access-Control-Allow-Origin': '*',
            'Accept': 'application/json, text/plain, */*'
        },
        // 设置允许cors跨域
        mode: 'cors'
    });
    return result;
}

// 将对象拼接成 key1=val1&key2=val2&key3=val3 的字符串形式
function obj2params(obj) {
    let result = '';
    let item;
    for (item in obj) {
        result += '&' + item + '=' + encodeURIComponent(obj[item]);
    }
    
    if (result) {
        result = result.slice(1);
    }
    
    return result;
}

// 发送 post 请求
export function post(url, paramsObj) {
    let result = fetch(url, {
        method: 'POST',
        credentials: 'include',
        headers: {
            'Accept': 'application/json, text/plain, */*',
            'Content-Type': 'application/x-www-form-urlencoded'
        },
        body: obj2params(paramsObj)
    });
    
    return result;
}

Create a publicnew mockdirectory under the directory place the simulation data.
Create a new file in the directorymock .list.json

public > mock > list.json

{
    "errorNo": 0,
    "message": "success",
    "data": [
        {
            "name": "Kelli",
            "age": 12
        },
        {
            "name": "Vivien",
            "age": 17
        },
        {
            "name": "Jacklyn",
            "age": 19
        },
        {
            "name": "Bobbie",
            "age": 32
        }
    ]
}

Modify the file src> .containersList.js

src > containers > List.js

import React, {Component} from 'react';
import {get} from '../fetch/index';

class List extends Component {
    constructor(props) {
        super(props);
        this.state = {}
    }
    componentWillMount() {
        this.getListData()
    }
    getListData() {
        get("./mock/list.json").then((res) => {
            return res.json();
        }).then((json)=>{
            this.setState({
                dataList: json.data
            })
        }).catch(function (err) {
            console.log(err);
        })
    }
    
    render() {
        let _this = this;
        function createListDom() {
            return {
                __html: _this.state.dataList && _this.state.dataList.map( item => {
                    return '<li>name: '+ item.name + ',age: '+ item.age +'</li>'
                }).join('')
            };
        }
        return (
            <div>
                List <br/>
                <ul dangerouslySetInnerHTML={createListDom()} />
            </div>
        );
    }
}

export default List;

This is just a simple test of the get method. As for the post request, anyone who is interested can test it in private.
The configuration is completed as shown below:

Step 5 (Configure sass)

In the high version of create-react-app, the function of supporting sass has been removed. If we still want to use it and can only configure it ourselves, we need to change the configuration file.
1. Install dependencies

yarn add node-sass sass-loader --save-dev

2. Modify the configuration

Find the filenode_modules/react-scripts/config under , first add it in the back according to the rules , and then configure the sass file rules in .webpack.config.dev.js
exclude/.scss$/
loaders

{
    test: /\.scss$/,
    loaders: ['style-loader', 'css-loader', 'sass-loader']
}

After changing the configuration of the two places, sass is configured, as shown in the figure:

webpack.config.dev.jsIt is the configuration file of the development environment. If you want to take effect in the production environment, you are webpack.config.prod.jsdoing the same configuration modification.

At this point, all the configuration is complete. The pro-test of the project can be run.

Author HoChine
April 27, 2018
Project demo: http://hochine.cn/demo/react-demo
GitHub address: https://github.com/HoChine/react-demo

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324976866&siteId=291194637