美文网首页
react项目实战笔记

react项目实战笔记

作者: 三天两觉_ | 来源:发表于2020-12-01 22:29 被阅读0次

    项目实战

    1.脚手架生成项目

    create-react-app jianshu
    

    2.styled-components的使用

    • 1.安装styled-components包
    yarn add styled-components
    
    • 2.创建style.js文件,代码如下
    import { createGlobalStyle  } from "styled-components";
    //导出全局样式
    export const GlobalStyle = createGlobalStyle `
    //此处是全局样式表,可以把reset.css放在这里
    html, body, div, span{...}
    `
    
    • 3.在index.js中引入,代码如下
    import React from 'react';
    import ReactDOM from 'react-dom';
    //引入全局样式
    import {GlobalStyle} from "./css/style.js";
    import App from './App';
    
    ReactDOM.render(
      <React.StrictMode>
        /*全局样式*/
        <GlobalStyle />
        <App />
      </React.StrictMode>,
      document.getElementById('root')
    );
    

    3.在组建中使用styled-components

    • header组件的编写
      • header组件目录结构如下


        image.png
        • header (文件夹)
          • index.js (header组件的代码)
          • style.js (header组件的样式)
      • index.js代码如下
    import react,{Component} from "react";
    import {HeaderWrapper,NavLogo,Nav,NavLeft,NavRight,HeaderLink,LinkItem} from "./style"
    
    class header extends Component{
        render(){
            return (
                <HeaderWrapper>
                    <NavLogo href="/"></NavLogo>
                    <Nav>
                        <NavLeft>
                            <p className="p1">首页</p>
                            <p className="p2">下载APP</p>
                            <input type="text" placeholder="搜索"/>
                        </NavLeft>
                        <NavRight>
                            <p>Aa</p>
                            <a href="">登录</a>
                        </NavRight>
                    </Nav>
                    <HeaderLink>
                        <LinkItem>注册</LinkItem>    
                        <LinkItem className="link2">写文章</LinkItem>    
                    </HeaderLink>  
                </HeaderWrapper>
            )
        }
    }
    export default header;
    

    style.js代码如下

    import styled from "styled-components";
    //引入图片
    import logoImg from "../../asstes/img/nav-logo.png";
    //HeaderWrapper会被解析成div元素 模板字符串中写样式,把HeaderWrapper暴露出去,在组件中使用就不会产生样式冲突问题了。
    export const HeaderWrapper = styled.div`
      display: flex;
      height: 58px;
      padding: 0 39px;
      border-bottom:1px solid #eee;
    `;
    //NavLogo会被解析成a标签 注意图片要用import的方式
    export const NavLogo = styled.a`
      background: url("${logoImg}") no-repeat;
    `;
    //NavLeft有子元素,子元素样式的写法
    export const NavLeft = styled.div`
      NavLeft的样式
      .p1{
          p1的样式
      }
      .p2{
          p2的样式
      }
      input{
          input的样式
      }
    `;
    //其他代码省略....
    

    4.使用redux改造代码

    import  { Component } from "react";
    import {connect} from "react-redux";
    
    import {changeFocusStatus} from "../../store/actionCreator";
    class header extends Component {
      constructor(props){
        super(props);
        this.state = {
          focus:false
        }
      }
      render() {
        const {props} = this;
        return (
          <HeaderWrapper>
            /*重点代码 其他代码省略*/
            <div className="search" className={props.foucsed==true?"search focus":"search"} >
                <input type="text" placeholder="搜索" onFocus={()=>{props.changeFoucs(true)}} onBlur={()=>{props.changeFoucs(false)}} />
                <span className="iconfont icon-fangdajing"></span>
             </div> 
          </HeaderWrapper>
        );
      }
    }
    const mapStateToProps = (state)=>{
      return {
        foucsed:state.foucsed
      }
    }
    const mapActionToProps = (dispatch)=>{
      return {
        changeFoucs(value){
          const action = changeFocusStatus(value);
          dispatch(action)
        }
      }
    }
    export default connect(mapStateToProps,mapActionToProps)(header);
    
    5.拆分reducer.js,然后使用combineReducers进行组合,类似于vue的store拆分
    • reducer.js代码
    import { combineReducers } from "redux";
    import { reducer as HeaderReducer } from "../common/header/store";
    
    const reducer = combineReducers({
        header:HeaderReducer
    });
    
    export default reducer;
    
    • 在header组件中创建store文件夹,下面存放actionCreators、reducer.js、actionTypes(更改文件名字为constant.js),之后在index.js中把三个文件引入统一对外暴露。目录结构如下图所示:


      image.png
    • index.js代码
    import reducer from "./reduce";
    import * as constant from "./constant";
    import * as actionCreators from "./actionCreators";
    
    export { reducer , constant , actionCreators }
    
    • reducer.js代码
    import {CHANGE_FOUCS_STATUS} from "./constant";
    const defaultStore = {
        foucsed:false
    };
    export default (store = defaultStore, action) => {
        if(action.type==CHANGE_FOUCS_STATUS){
            const newStore = JSON.parse(JSON.stringify(store));
            newStore.foucsed = action.value;
            return newStore;
        }
        return store;
    };
    

    constant.js(也就是actionTypes.js)代码 constant是常量的意思

    export const CHANGE_FOUCS_STATUS = "change_foucs_status";
    

    actionCreators.js代码

    import { CHANGE_FOUCS_STATUS } from "./constant";
    
    export const changeFocusStatus = (value) => {
      return {
        type: CHANGE_FOUCS_STATUS,
        value,
      };
    };
    
    • 最后修改header组件index.js代码引入constant.js(也就是actionTypes.js)的方式
    //其他代码省略
    import { actionCreators } from "./store";
    const mapActionToProps = (dispatch)=>{
      return {
        changeFoucs(value){
          const action = actionCreators.changeFocusStatus(value);
          dispatch(action)
        }
      }
    }
    

    5.使用immutable包保证state中的数据不被修改(防止写代码误操作)

    • 默认的数据在reducer.js中,改造reducer.js代码
    import { CHANGE_FOUCS_STATUS } from "./constant";
    //引入immutable库,mutable"可变的"的意思,immutable"不可变的"意思 
    import { fromJS } from "immutable";
    //通过fromJS方法传入一个对象,得到一个immutable对象
    const defaultStore = fromJS({
      focused: false,
    });
    export default (store = defaultStore, action) => {
      if (action.type == CHANGE_FOUCS_STATUS) {
        // immutable对象的set方法,会结合之前immutable对象(也就是defaultStore)的值和要设置的值,返回一个全新的immutable对象,并不会对之前的对象做修改。
        return store.set("focused",action.value);
      }
      return store;
    }; 
    
    • 由于store变成了一个immutable对象,所以获取值的方式也需要改变。
    //header组件代码改动
    const mapStateToProps = (state)=>{
      return {
        //由于
        focused:state.header.get("focused")
      }
    }
    

    6.在总的reducer.js中结合dedux-immutable库把最外层的reducer对象也变成immutable对象,改造代码如下:

    // import { combineReducers } from "redux";
    //引入包的时候combineReducers从redux-immutable引入就可以了。
    import { combineReducers } from "redux-immutable";
    import { reducer as HeaderReducer } from "../common/header/store";
    const reducer = combineReducers({
        header:HeaderReducer
    });
    export default reducer;
    
    • 由于整个reducer返回的都是一个immutable对象,所以在页面中使用的时候都需要用get方法获取数据,改造header组件代码如下:
    const mapStateToProps = (state)=>{
      return {
        // focused:state.get("header").get("focused")
        //下面的写法等价于上面的写法
        focused:state.getIn(["header","focused"])
      }
    }
    

    7.搜索框聚焦,请求搜索历史数据,使用redux-thunk中间件,把异步请求数据操作写在actionCreator中。效果如下:

    image.png
    • store\index.js文件 加入中间件redux-thunk
    import { createStore, compose, applyMiddleware } from "redux";
    import reducer from "./reducer";
    import thunk from "redux-thunk";
    const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
    const store = createStore(reducer, composeEnhancers(
        applyMiddleware(thunk)
    ));
    export default store;
    
    • actionCreators.js 导出函数,在该函数中请求异步数据并通过dispatch方法传递action给store
    //注意一个小细节,由于header中的store数据是调用fromJS得到的immutable数据,所以此处把拿到的数据也转换成immutable数据
    import { fromJS } from "immutable";
    const setKeywordList = (list) => ({
      type: KEYWORD_LIST,
      list:fromJS(list)
    });
    //暴露出去一个函数
    export const getKeywordList = (data)=>{
      return async (dispatch)=>{
        const {data} = await axios.get("http://127.0.0.1:5500/data/headerList.json");
        const action = setKeywordList(data.list)
        dispatch(action);
      }
    }
    
    • header\store\reduce.js 代码改造,改变if为switch
    import { CHANGE_FOUCS_STATUS,KEYWORD_LIST } from "./constant";
    //引入immutable库,mutable"可变的"的意思,immutable"不可变的"意思 
    import { fromJS } from "immutable";
    //通过fromJS方法传入一个对象,得到一个immutable对象
    const defaultStore = fromJS({
      focused: false,
      list:["罗小黑","刺客伍六七"]
    });
    export default (store = defaultStore, action) => {
      switch(action.type){
        case CHANGE_FOUCS_STATUS:
          // immutable对象的set方法,会结合之前immutable对象的值和要设置的值,返回一个全新的对象。
          return store.set("focused",action.value); 
        case KEYWORD_LIST:
          return store.set("list",action.list);
        default:
          return store
      }
    };
    
    • header\index.js 头部组件
    import { Component } from "react";
    import { connect } from "react-redux";
    import { actionCreators } from "./store";
    class header extends Component {
      //渲染历史记录
      getHisTory(state, list) {
        if (state) {
          return (
            <History>
              {list.map((item) => {
                return (
                  <div className="item" key={item}>
                    <div className="item__left">
                      <i className="iconfont icon-clock"></i>
                      <span>{item}</span>
                    </div>
                    <i className="iconfont icon-chahao"></i>
                  </div>
                );
              })}
            </History>
          );
        }
      }
      render() {
        const { focused,changeFoucs,list } = this.props;
        return (
          <NavLeft>
            <p className="p1">首页</p>
            <p className="p2">下载APP</p>
            <div className={focused == true ? "search focus" : "search"}>
              <input
                type="text"
                placeholder="搜索"
                onFocus={() => {
                  changeFoucs(true);
                }}
                onBlur={() => {
                  changeFoucs(false);
                }}
              />
              <span className="iconfont icon-fangdajing"></span>
              {this.getHisTory(focused, list)}
            </div>
          </NavLeft>
        );
      }
    }
    const mapStateToProps = (state) => {
      return {
        focused: state.getIn(["header", "focused"]),
        list: state.getIn(["header", "list"]),
      };
    };
    const mapActionToProps = (dispatch) => {
      return {
        changeFoucs(value) {
          const action = actionCreators.changeFocusStatus(value);
          dispatch(action);
          //如果聚焦,就去请求后端数据
          if(value)dispatch(actionCreators.getKeywordList())
        }
      };
    };
    export default connect(mapStateToProps, mapActionToProps)(header);
    

    相关文章

      网友评论

          本文标题:react项目实战笔记

          本文链接:https://www.haomeiwen.com/subject/ukpewktx.html