关于react.js:React-仿简书项目实战

0次阅读

共计 5835 个字符,预计需要花费 15 分钟才能阅读完成。

我的项目源码

https://github.com/astak16/ac…

我的项目构造

src/common; // 公共组件
src/pages; // 页面
src/static; // 动态资源
src/store; // 主 store
App.js; // 根组件
index.css; // 款式
index.js; // 入口文件

重置 css

搜寻reset.css,复制过去

styled-components

css文件一旦在一个文件中被引入,会在全局中失效

这样写 css 会有些问题,当页面中有多个组件时,款式存在被笼罩的危险

咱们心愿在写款式的时候,每个组件的款式是独立的,不会相互的影响

应用

  1. index.css 重命名为style.js
  2. index.js 引入style.js

    import "style.js";
  3. style.js

    import {injectGlobal} from "styled-components";
    
    injectGlobal`
      body{padding: 10px}
    `;

在组件中应用

组件申明

// Header/style.js
import styled from "styled-components";

export const HeaderWrapper = styled.div`
  height: 56px;
`;

// Header/index.js
import {HeaderWrapper} from "./style";

class Header extends Component {render() {return <HeaderWrapper></HeaderWrapper>;}
}

图片应用

style.js 中应用背景图片的话,间接应用 background: url('/images/logo.png') 是没有成果的,因为 webpack 在打包的时候,不晓得工程目录是啥样的,它会把门路当成字符串

须要这样写

import logoPic from "/images/logo.png";

export const Logo = style.a`
  background: url(${logoPic})
`;

设置属性

import logoPic from "/images/logo.png";

export const Logo = style.a.attr({href: "/",})`
  background: url(${logoPic})
`;

参数传递

组件中要传递不同的参数进来,styled提供了函数性能

<RecommendItem key='1' imgURL='/images/1.png'>1</RecommendItem>
<RecommendItem key='2' imgURL='/images/2.png'>1</RecommendItem>

// style.js
export const RecommendItem = styled.div`
  width: 280px;
  height: 50px;
  background: url(${props => props.imgURL});
  background-size: contain;
`

immutable.js

reducer 中,state的数据是不心愿被扭转的,在写我的项目的时候,很容易在人不知; 鬼不觉中把 state 给改了,从而造成异样。

immutable.js能够帮忙解决问题,它会生成一个 immutable 对象,这个对象是不可被扭转的。

immutable提供了 fromJS 的办法,能够把 js 对象转换成 immutable 对象

const a = fromJS({age: 18});

immutable提供了 getgetIn两种办法来读取数据

const a = fromJS({
  age: 18
  feature: {height: 180}
})

const age = a.get('age')

const height = a.getIn(['feature', 'height'])
// 或者
const height = a.get('feature').get('height')

immutable提供了 setmerge两种办法来设置数据。

immutable对象的 set 办法,会联合之前的 immutable 对象的值,和设置的值,返回一个全新的对象。它并不会去改之前的 immutable 数据。

const a = fromJS({
  age: 18,
  name: "uccs",
});
a.set("age", 19).set("name", "tiantain");
// 或者
a.merge({
  age: 1,
  name: "tiantian",
});

当最里面应用 immutable 对象时,外部的 Object 类型的数据也会变成 immutable 类型,所以在应用 set 设置时,先要把一般对象变成 immutable 对象才行。

const a = fromJS({list: [], // 这个 list 也是 immutable 数组
});

const data = [1, 2, 3];
a.set("list", fromJS(data));

immutable.js提供了 toJS 办法,是为了将 immutable 对象转换成 js 对象

const a = fromJS({list: [1, 2, 3],
});

const b = a.toJS();
b[1];

redux-thunk

redux-thunk的作用是能够在 action 中写函数

redux

首页须要装置 reduxreact-redux

react-redux是不便在 react 中应用redux

redux的应用能够看:redux 学习笔记

store/index.js

// store/index.js
import {createStore, applyMiddleware, compose} from "redux";
import thunk from "redux-thunk";
import reducer from "./reducer";

const store = createStore(reducer, compose(applyMiddleware(thunk))); // 在 store 中应用 redux-thunk

export default store;

store/reducer.js

// 主 store/reducer.js
import {combineReducers} from "redux-immutable";
import {headerReducer} from "../common/header/store";

export default combineReducers({header: headerReducer,});

// 分 header/store/reducer.js
import {Search_Focus} from "./actionType";
import {fromJS} from "immutable";
const defaultState = fromJS({focused: false, // 默认数据});
export default (state = defaultState, action) => {switch (action.type) {
    case Search_Focus:
      return state.set("focused", action.data);
    default:
      return state;
  }
};

redux-immutable提供了一个 combineReducers 办法,这个办法用来组合各个拆分进去的reducer

header/store/actionCreators.js

// header/store/actionCreators.js
import {Search_Focus} from './actionType'

const searchFocus = (data) => {
  type: Search_Focus,
  data
}

export const getList = async () => {return (dispatch) => {const res = await axios.get('api/header.json')
    dispatch(searchFocus(res.data))
  }
}

header/store/actionType.js

// header/store/actionType.js
export const Search_Focus = "header/search_focus";

App.js

// App.js
import {Provider} from "react-redux";
import store from "./store";

<Provider store={store}>
  <BrowserRouter>
    <div>
      <Header />
    </div>
  </BrowserRouter>
</Provider>;

react-redux有一个外围组件 Provider,这个组件有一个store 属性,将咱们定义的 store 传给它,这样 Provider 外面所有组件都有能力去应用 store 中的数据了

组件连贯 store

Providerstore 提供给了各组件,然而组件想应用 store 中的数据,还要做连贯

import {connect} from "react-redux";

class Header extends React.Component {}

export default connect()(Header);

react-redux提供了 connect 办法,connect就是帮忙组件和 store 建设连贯的。
connect接管两个参数:mapStateToPropsmapDispatchToProps

import {actionCreators} from "./store/actionCreators";

const mapStateToProps = (state) => {
  return {focused: state.getIn(["header", "focused"]),
  };
};

const mapDispatchToProps = (dispatch) => {
  return {handleInputFocus() {dispatch(actionCreators.getList());
    },
  };
};
export default connect(mapStateToProps, mapDispatchToProps)(Header);

组件中应用this.props.focused

react-router-dom

Route

  • render办法能够渲染一个货色
  • exact齐全匹配门路

    • exactfalse 时,//detail 都能匹配上
  • component渲染组件
import {BrowserRouter, Route} from "react-router-dom";
import Home from "./pages/home";
import Detail from "./pages/detail/loadable";

function App() {
  return (<Provider store={store}>
      <BrowserRouter>
        <div>
          <Route path="/" exact component={Home} />
          <Route path="/detail/:id" exact component={Detail} />
        </div>
      </BrowserRouter>
    </Provider>
  );
}

export default App;

动画

换一换旁边有个 icon,每次点击的时候,这个icon 须要转动起来。

每次点击的时候只有扭转 icontrannform: rotate() 的值就能够了。每次减少 360°

通过 ref 能够获取到 react 渲染进去的实在节点。

<SearchInfoSwitch onClick={() => handleChangePage(this.spinIcon)}>
  <i className='iconfont spin'
     ref={icon => this.spinIcon = icon}
  >&#xe852;</i>
换一批 </SearchInfoSwitch>

handleChangePage(spin) {let originAngle = spin.style.transform.replace(/[^0-9]/ig, '')
  if (originAngle)
    originAngle = parseInt(originAngle, 10)
  else
    originAngle = 0

  spin.style.transform = `rotate(${originAngle + 360}deg)`
}

其余

  1. Link 代替 a 做跳转,能够做到按需加载
  2. PureComponent组件等价于Component+shouldComponentUpdate
  3. dangerouslySetInnerHTML={{__html: '<div> 文本 </div>'}}能够渲染 HTML 内容
  4. <Route path='/detail/:id'/>路由参数获取this.props.match.params.id
  5. 异步组件redux-immutable,应用异步组件时须要用withRouterexport default connect(mapState, mapDispatch)(withRouter(Detail));

    // detail/loadable.js
    import React from "react";
    import Loadable from "react-loadable";
    
    const LoadableComponent = Loadable({loader: () => import("./"),
      loading() {return <div> 正在加载 </div>;},
    });
    
    export default () => <LoadableComponent />;
    
    // App.js
    import Detail from "./pages/detail/loadable";

总结

路由

我的项目技术栈:

  • react-router:路由
  • react-redux:数据挂你工具
  • react-loadable:按需加载
  • react-transition-group:动画
  • redux-immutable:将 state 变成 immutable 对象
  • redux-thunk:能够在 action 中应用函数
  • styled-components:部分款式
  • axiosajax申请
正文完
 0