美文网首页
React 16.4 开发简书项目[7]

React 16.4 开发简书项目[7]

作者: Mark同学 | 来源:发表于2019-11-26 00:38 被阅读0次

第7章 项目实战:Header组件开发

7-1 项目目录搭建:Styled-Components 与 Reset.css 的结合使用

安装

https://reactjs.org/
npx create-react-app jianshu
cd jianshu
npm start

打包,并在本地起一个 server 运行*

npm run build
npm i -g serve
serve -s build

删除一些文件

src
——App.css

.App {
  text-align: center;
}

.App-logo {
  height: 40vmin;
}

.App-header {
  background-color: #282c34;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white;
}

.App-link {
  color: #09d3ac;
} 

src
——App.test.js

 import React from 'react';
 import ReactDOM from 'react-dom';
 import App from './App';

 it('renders without crashing', () => {
   const div = document.createElement('div');
   ReactDOM.render(<App />, div);
   ReactDOM.unmountComponentAtNode(div);
});

修改一些文件

在项目的入口文件引入样式

src
——index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));
给根组件添加一个简单的颜色样式

src
——index.css

body {
  margin: 0;
  padding: 0;
}

.dell {
  background: orange;
}
这种样式的引入方式,全局组件可用

src
——App.js

import React from 'react';

function App() {
  return (
    <div className="dell">
      Hello,World!
    </div>
  );
}

export default App;

避免样式冲突

引入第三方模块 styled-components 对样式进行管理

npm i styled-components
npm i typescript

通过 styled-components 构建全局样式

index.css —— style.js

import { createGlobalStyle } from 'styled-components';
export const GlobalStyle = createGlobalStyle`
  body {
    margin: 0;
    padding: 0;
  }
  .dell {
    background: orange;
  }
`
在入口文件引入全局样式

src
——index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './style.js';

ReactDOM.render(<App />, document.getElementById('root'));
在根组件中使用全局样式
  • 根组件相当于 index.html

src
——App.js

import React from 'react';
import { GlobalStyle } from './style';

function App() {
  return (
    <div className="dell">
      <GlobalStyle />
      Hello,World!
    </div>
  );
}

export default App;

在所有的浏览器中统一样式 reset.css

https://meyerweb.com/eric/tools/css/reset/
src
——style.js

import { createGlobalStyle } from 'styled-components';
export const GlobalStyle = createGlobalStyle`
  html, body, div, span, applet, object, iframe,
  h1, h2, h3, h4, h5, h6, p, blockquote, pre,
  a, abbr, acronym, address, big, cite, code,
  del, dfn, em, img, ins, kbd, q, s, samp,
  small, strike, strong, sub, sup, tt, var,
  b, u, i, center,
  dl, dt, dd, ol, ul, li,
  fieldset, form, label, legend,
  table, caption, tbody, tfoot, thead, tr, th, td,
  article, aside, canvas, details, embed, 
  figure, figcaption, footer, header, hgroup, 
  menu, nav, output, ruby, section, summary,
  time, mark, audio, video {
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    font: inherit;
    vertical-align: baseline;
  }
  /* HTML5 display-role reset for older browsers */
  article, aside, details, figcaption, figure, 
  footer, header, hgroup, menu, nav, section {
    display: block;
  }
  body {
    line-height: 1;
  }
  ol, ul {
    list-style: none;
  }
  blockquote, q {
    quotes: none;
  }
  blockquote:before, blockquote:after,
  q:before, q:after {
    content: '';
    content: none;
  }
  table {
    border-collapse: collapse;
    border-spacing: 0;
  }
`;

7-2 使用 styled-components 完成 Header 组件布局(1)

因为头部是公共区块,所以文件夹命名为 common

src
——common
————header
——————index.js

import React from 'react';

function Header() {
  return (
    <div>
      Header
    </div>
  );
}

export default Header;

在入口组件里引用我们自定义的 Header 组件

src
——App.js

import React from 'react';
import { GlobalStyle } from './style';
import Header from './common/header';

function App() {
  return (
    <div>
      <GlobalStyle />
      <Header />
    </div>
  )
}

export default App;

开始写头部样式:组件局部样式的应用

src
——common
————header
——————style.js

import styled from 'styled-components';
export const HeaderWrapper = styled.div`
  height: 56px;
  background: red;
`;

src
——common
————header
——————index.js

import React from 'react';
import { HeaderWrapper } from './style';

function Header() {
  return (
    <HeaderWrapper>
      Header
    </HeaderWrapper>
  );
}

export default Header;

将静态文件统一放在 statics 目录里管理

src
——statics
——————logo.png

引入 Logo 组件

src
——common
————header
——————index.js

import React from 'react';
import { HeaderWrapper, Logo } from './style';

function Header() {
  return (
    <HeaderWrapper>
      <Logo />
    </HeaderWrapper>
  );
}

export default Header;

定义 Logo 组件

src
——common
————header
——————style.js

import styled from 'styled-components';

export const HeaderWrapper = styled.div`
  position: relative;
  height: 56px;
  border-bottom: 1px solid #f0f0f0;
`;

export const Logo = styled.a`
  position: absolute;
  top: 0;
  left: 0;
  display: block;
  width: 100px;
  height: 56px;
  background: orange;
`;

引入图片地址的语法

src
——common
————header
——————style.js

import styled from 'styled-components';
import logoPic from '../../statics/logo.png';

// ...

export const Logo = styled.a`
  position: absolute;
  top: 0;
  left: 0;
  display: block;
  width: 100px;
  height: 56px;
  background-image: url(${logoPic});
  background-size: contain;
  cursor: pointer;
`;

a标签添加跳转链接

import styled from 'styled-components';
import logoPic from '../../statics/logo.png';

// ...

export const Logo = styled.a.attrs({
  href: "/"
})`
  position: absolute;
  ...
  cursor: pointer;
`;

导航样式

src
——common
————header
——————style.js

import styled from 'styled-components';

// ...

export const Nav = styled.div`
  width: 960px;
  height: 100%;
  margin: 0 auto;
`;

7-3 使用styled-components完成Header组件布局(2)

导航项既有相同点、又有不同点,通过 class 来区分

src
——common
————header
——————index.js

import React from 'react';
import {
  HeaderWrapper,
  Logo,
  Nav,
  NavItem
} from './style';

function Header() {
  return (
    <HeaderWrapper>
      <Logo/>
      <Nav>
        <NavItem className="left active">首页</NavItem>
        <NavItem className="left">下载App</NavItem>
        <NavItem className="right">登录</NavItem>
        <NavItem className="right">Aa</NavItem>
      </Nav>
    </HeaderWrapper>
  );
}

export default Header;

src

——common
————header
——————style.js

import styled from 'styled-components';

// ...

export const NavItem = styled.div`
    padding: 0 15px;
    font-size: 17px;
    line-height: 56px;
    color: #333;
    &.left {
        float: left;
    }
    &.right {
        float: right;
        color: #969696;
    }
    &.active {
        color: #ea6f5a;
    }
`;

引入搜索框

src
——index.js

import React from 'react';
import {
  HeaderWrapper,
  Logo,
  Nav,
  NavItem,
  NavSearch
} from './style';

function Header() {
  return (
    <HeaderWrapper>
      <Logo/>
      <Nav>
        <NavItem className="left active">首页</NavItem>
        <NavItem className="left">下载App</NavItem>
        <NavItem className="right">登录</NavItem>
        <NavItem className="right">Aa</NavItem>
        <NavSearch></NavSearch>
      </Nav>
    </HeaderWrapper>
  );
}

export default Header;

定义搜索框样式

src
——common
————header
——————style.js

export const NavSearch = styled.input.attrs({
    placeholder: '搜索'
})`
    width: 160px;
    height: 38px;
    padding: 0 20px;
    margin-top: 9px;
    margin-left: 20px;
    box-sizing: border-box;
    border: none;
    outline: none;
    border-radius: 19px;
    background: #eee;
    font-size: 14px;
    &::placeholder {
        color: #999;
    }
`;

引入最右侧的两个按钮

src
——index.js

import React from 'react';
import {
  HeaderWrapper,
  Logo,
  Nav,
  NavItem,
  NavSearch,
  Addition,
  Button
} from './style';

function Header() {
  return (
    <HeaderWrapper>
      <Logo />
      <Nav>
        <NavItem className='left active'>首页</NavItem>
        <NavItem className='left'>下载App</NavItem>
        <NavItem className='right'>登录</NavItem>
        <NavItem className='right'>Aa</NavItem>
        <NavSearch></NavSearch>
      </Nav>
      <Addition>
        <Button className='writting'>写文章</Button>
        <Button className='reg'>注册</Button>
      </Addition>
    </HeaderWrapper>
  )
}

export default Header;

定义按钮样式

src
——common
————header
——————style.js

// ...
export const Nav = styled.div`
  ...
  padding-right: 70px;
  box-sizing: border-box;
  ...
`;
// ...
export const Addition = styled.div`
    position: absolute;
    right: 0px;
    top: 0px;
    height: 56px;
`;

export const Button = styled.div`
    float: right;
    margin-top: 9px;
    margin-right: 20px;
    padding: 0 20px;
    line-height: 38px;
    border-radius: 19px;
    border: 1px solid #ec6149;
    font-size: 14px;
    &.reg {
        color: #ec6149;
    }
    &.writting {
        color: #fff;
        background: #ec6149;
    }
`;

7-4 使用iconfont嵌入头部图标

iconfont.cn

1.png
2.png
3.png
4.png
5.png
6.png
7.png
8.png
9.png
10.png
11.png
12.png
13.png
14.png
15.png
16.png
17.jpeg
import './statics/iconfont/iconfont.css'
20.png
21.png
22.png
23.png
<i className="iconfont">&#xe636;</i>
<i className="iconfont">&#xe615;</i>
<i className="iconfont">&#xe60b;</i>

给搜索框增加放大镜图标

src
——index.js

import React from 'react';
import {
  HeaderWrapper,
  Logo,
  Nav,
  NavItem,
  NavSearch,
  Addition,
  Button,
  NavSearchWrapper
} from './style';

function Header() {
  return (
    <HeaderWrapper>
      <Logo/>
      <Nav>
        <NavItem className="left active">首页</NavItem>
        <NavItem className="left">下载App</NavItem>
        <NavItem className="right">登录</NavItem>
        <NavItem className="right">
          <i className="iconfont">&#xe636;</i>
        </NavItem>
        <NavSearchWrapper>
            <NavSearch></NavSearch>
            <span className='iconfont'>&#xe60b;</span>
        </NavSearchWrapper>
      </Nav>
      <Addition>
          <Button className='writting'>
            <i className="iconfont">&#xe615;</i>
            写文章
          </Button>
          <Button className='reg'>注册</Button>
      </Addition>
    </HeaderWrapper>
  );
}

export default Header;

给搜索框增加 wrapper 样式

控制放大镜在搜索框里的位置

src
——common
————header
——————style.js

export const NavSearchWrapper = styled.div`
   position: relative;
   float: left;
   .iconfont {
       position: absolute;
       right:5px;
       bottom: 5px;
       width: 30px;
       line-height: 30px;
       border-radius: 15px;
       text-align: center;
   }
`;

7-5 搜索框动画效果实现

搜索框样式微调

src
——common
————header
——————style.js

export const NavSearch = styled.input.attrs({
    placeholder: '搜索'
})`
    ...
    padding: 0 40px 0 20px;
    color: #666;
    ...
`;

给搜索框加 onFocus 事件,改变框的长度

src
——index.js

import React, { Component } from 'react';
import {
  HeaderWrapper,
  Logo,
  Nav,
  NavItem,
  NavSearch,
  Addition,
  Button,
  NavSearchWrapper
} from './style';

class Header extends Component {

    constructor(props) {
        super(props);
        this.state = {
            focused: false
        }
        this.handleInputFocus = this.handleInputFocus.bind(this);
        this.handleInputBlur = this.handleInputBlur.bind(this);
    }

    render() {
        return (
            <HeaderWrapper>
                <Logo />
                <Nav>
                    <NavItem className='left active'>首页</NavItem>
                    <NavItem className='left'>下载App</NavItem>
                    <NavItem className='right'>登录</NavItem>
                    <NavItem className='right'>
                        <span className='iconfont'>&#xe636;</span>
                    </NavItem>
                    <NavSearchWrapper>
                        <NavSearch
                            className={this.state.focused ? 'focused' : ''}
                            onFocus={this.handleInputFocus}
                            onBlur={this.handleInputBlur}
                        ></NavSearch>
                        <i className={this.state.focused ? 'focused iconfont' : 'iconfont'}>&#xe60b;</i>
                    </NavSearchWrapper>
                </Nav>
                <Addition>
                    <Button className='writting'>
                        <span className='iconfont'>&#xe615;</span>
                        写文章
                    </Button>
                    <Button>注册</Button>
                </Addition>
            </HeaderWrapper>
        )
    }

    handleInputFocus() {
        this.setState({
           focused: true
        })
    }

    handleInputBlur() {
        this.setState({
           focused: false
        })
    }
}

export default Header;

增加搜索框和放大镜聚焦样式

src
——common
————header
——————style.js

// ...

export const NavSearch = styled.input.attrs({
    placeholder: '搜索'
})`
    padding: 0 40px 0 20px;
    ...
    &::placeholder {
        color: #999;
    }
    &.focused {
        width: 240px;
    }
`;

// ...

export const NavSearchWrapper = styled.div`
   position: relative;
   float: left;
   .iconfont {
       ...
       text-align: center;
       &.focused {
           background: #777;
           color: #FFF;
       }
   }
`;

给搜索框添加动画效果

https://github.com/reactjs/react-transition-group

npm i react-transition-group

import { CSSTransition } from 'react-transition-group';

// ...

<NavSearchWrapper>
  <CSSTransition
    in={this.state.focused}
    timeout={500}
    classNames="slide"
  >
    <NavSearch
      className={this.state.focused ? 'focused' : ''}
      onFocus={this.handleInputFocus}
      onBlur={this.handleInputBlur}
    ></NavSearch>
  </CSSTransition>
  <i className={this.state.focused ? 'iconfont focused' : 'iconfont'}>&#xe60b;</i>
</NavSearchWrapper>

// ...

src
——common
————header
——————style.js

const NavSearch = styled.input.attrs({
    placeholder: '搜索'
})`
    padding: 0 40px 0 20px;

    ...

    &.focused {
        width: 240px;
    }
    &.slide-enter {
        transition: all .5s ease-out;
    }
    &.slide-enter-active {
        width: 240px;
    }
    &.slide-exit {
        transition: all .5s ease-out;
    }
    &.slide-exit-active {
        width: 160px;
    }
`;

7-6使用React-Redux进行应用数据的管理

1.创建 store

npm i redux
npm i react-redux
src
——store
————index.js

import { createStore } from 'redux';
import reducer from './reducer'

const store = createStore(reducer);

export default store;

src
——store
————reducer.js

const defaultState = {};

export default (state = defaultState, action) => {
  return state;
}

2.引用 store

src
——App.js

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

<Provider store={store}>
  <Header>
</Provider>

3.连接 store

src
——common
————header
——————index.js

import { connect } from 'react-redux';

// ...

const mapStateToProps = (state) => {
    return {

    }
}

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

4.将默认数据放到 redux 仓库进行管理

src
——common
————header
——————index.js

    constructor(props) {
         super(props);
    //     this.state = {
    //         focused: false
    //     }
         this.handleInputFocus = this.handleInputFocus.bind(this);
         this.handleInputBlur = this.handleInputBlur.bind(this);
     }

src
——store
————reducer.js

const defaultState = {
  focused: false
};

5.将 store 里的数据映射到组件的 Props

src
——common
————header
——————index.js

const mapStateToProps = (state) => {
    return {
      focused: state.focused
    }
}

6.将 this.state 都换成 this.props

src
——common
————header
——————index.js

<NavSearchWrapper>
  <CSSTransition
    in={this.props.focused}
    ...
  >
    <NavSearch
      className={this.props.focused ? 'focused' : ''}
      onFocus={this.props.handleInputFocus}
      onBlur={this.props.handleInputBlur}
    ></NavSearch>
  </CSSTransition>
  <i className={this.props.focused ? 'iconfont focused' : 'iconfont'}>&#xe60b;</i>
</NavSearchWrapper>

7.修改 redux 里数据的流程:

创建 action —— 给到 store——— 给到 reducer —— 返回给 store —— 数据发生更新 —— 页面跟着变化
src
——common
————header
——————index.js

    // constructor(props) {
    //     super(props);
    //     this.state = {
    //         focused: false
    //     }
    //     this.handleInputFocus = this.handleInputFocus.bind(this);
    //     this.handleInputBlur = this.handleInputBlur.bind(this);
    // }
    // handleInputFocus() {
    //     this.setState({
    //        focused: true
    //     })
    // }
    //
    // handleInputBlur() {
    //     this.setState({
    //        focused: false
    //     })
    // }
const mapDispatchToProps = (dispatch) => {
    return {
        handleInputFocus() {
            const action = {
                type: 'search_focus',
            }
            dispatch(action);
        },
        handleInputBlur() {
            const action = {
                type: 'search_blur'
            }
            dispatch(action);
        }
    }
}

src
——store
————reducer.js

export default (state = defaultState, action) => {
    if (action.type === 'search_focus') {
        return {
            focused: true
        }
    }
    if (action.type === 'search_blur') {
        return {
            focused: false
        }
    }
    return state;
}

8.变身无状态组件

src
——common
————header
——————index.js

const Header = (props) => {
  return (
    <HeaderWrapper>
    ...
    </HeaderWrapper>
  )
}
function Header(props) {
  return (
    <HeaderWrapper>
    ...
    </HeaderWrapper>
  )
}

9.将 this.props 改为 props

<NavSearchWrapper>
  <CSSTransition
    in={props.focused}
    ...
  >
    <NavSearch
      className={props.focused ? 'focused' : ''}
      onFocus={props.handleInputFocus}
      onBlur={props.handleInputBlur}
    ></NavSearch>
  </CSSTransition>
  <i className={props.focused ? 'iconfont focused' : 'iconfont'}>&#xe60b;</i>
</NavSearchWrapper>

10.去掉 { Component } 的引入

import React from 'react';
import { connect } from 'react-redux';
import { CSSTransition } from 'react-transition-group';
import {
  HeaderWrapper,
  Logo,
  Nav,
  NavItem,
  NavSearch,
  Addition,
  Button,
  NavSearchWrapper
} from './style';

function Header(props) {
    return (
        <HeaderWrapper>
            <Logo />
            <Nav>
                <NavItem className='left active'>首页</NavItem>
                <NavItem className='left'>下载App</NavItem>
                <NavItem className='right'>登录</NavItem>
                <NavItem className='right'>
                    <span className='iconfont'>&#xe636;</span>
                </NavItem>
                <NavSearchWrapper>
                    <CSSTransition
                    in={props.focused}
                    timeout={500}
                    classNames="slide"
                    >
                    <NavSearch
                        className={props.focused ? 'focused' : ''}
                        onFocus={props.handleInputFocus}
                        onBlur={props.handleInputBlur}
                    ></NavSearch>
                    </CSSTransition>
                    <i className={props.focused ? 'iconfont focused' : 'iconfont'}>&#xe60b;</i>
                </NavSearchWrapper>
            </Nav>
            <Addition>
                <Button className='writting'>
                    <span className='iconfont'>&#xe615;</span>
                    写文章
                </Button>
                <Button>注册</Button>
            </Addition>
        </HeaderWrapper>
    )
}

const mapStateToProps = (state) => {
    return {
        focused: state.focused
    }
}

const mapDispatchToProps = (dispatch) => {
    return {
        handleInputFocus() {
            const action = {
                type: 'search_focus',
            }
            dispatch(action);
        },
        handleInputBlur() {
            const action = {
                type: 'search_blur'
            }
            dispatch(action);
        }
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(Header);

7-7使用combineReducers完成对数据的拆分管理

1.设置开发者工具:redux-devtoola-extension

https://github.com/zalmoxisus/redux-devtools-extension

src
——store
————index.js

import { createStore, compose } from 'redux';
import reducer from './reducer'

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const store = createStore(reducer, composeEnhancers());

export default store;

2.一个文件的代码超过300行,就证明设计有问题

Reducer 是图书馆管理员对应的手册,把手册拆分成多个小手册来管理

src
——common
————header
——————store
————————reducer.js

const defaultState = {
  focused: false
};

export default (state = defaultState, action) => {
    if (action.type === 'search_focus') {
        return {
            focused: true
        }
    }
    if (action.type === 'search_blur') {
        return {
            focused: false
        }
    }
    return state;
};

3.在根目录下的 Reducer 对所有分类手册进行整合

src
——store
————reducer.js

import { combineReducers } from 'redux';
import headerReducer from '../common/header/store/reducer';

const reducer = combineReducers({
  header: headerReducer
})

export default reducer;

4.从 Store 获取数据的时候要多加一层

src
——common
————header
——————index.js

const mapStateToProps = (state) => {
    return {
      focused: state.header.focused
    }
}

5.优化分类手册的整合路径

src
——common
————header
——————store
————————index.js

import reducer from './reducer';

export { reducer };

src
——store
————reducer.js

import { reducer as headerReducer } from '../common/header/store';

7-8 actionCreators与constants的拆分

用 actionCreators 统一创建 action

src
——common
————header
——————store
————————actionCreators.js

export const searchFocus = () => ({
  type: 'search_focus'
});
export const searchFocus = () => ({
  type: 'search_blur'
});

src
——common
————header
——————index.js

import * as actionCreators from './store/actionCreators';

// ...

const mapDispatchToProps = (dispatch) => {
    return {
        handleInputFocus() {
            dispatch(actionCreators.searchFocus());
        },
        handleInputBlur() {
            dispatch(actionCreators.searchBlur());
        }
    }
}

统一管理常量

src
——common
————header
——————store
————————constants.js

export const SEARCH_FOCUS = 'header/SEARCH_FOCUS';
export const SEARCH_BLUR = 'header/SEARCH_BLUR';

src
——common
————header
——————store
————————actionCreators.js

import * as constants from './constants';
export const searchFocus = () => ({
  type: constants.SEARCH_FOCUS
});
export const searchBlur = () => ({
  type: constants.SEARCH_BLUR
});

src
——common
————header
——————store
————————reducer.js

import * as constants from './constants';

const defaultState = {
  focused: false
};

export default (state = defaultState, action) => {
    if (action.type === constants.SEARCH_FOCUS) {
        return {
            focused: true
        }
    }
    if (action.type === constants.SEARCH_BLUR) {
        return {
            focused: false
        }
    }
    return state;
};

整合 store 下路径

src
——common
————header
——————store
————————index.js

import reducer from './reducer';
import * as actionCreators from './actionCreators';
import * as constants from './constants';

export { reducer, actionCreators, constants };

src
——common
————header
——————index.js

import { actionCreators } from './store';

// ...

7-9 使用 Immutable.js 来管理store中的数据

https://immutable-js.github.io/immutable-js/docs/
https://github.com/immutable-js/immutable-js

npm i immutable

1.将 state 变成 immutable 对象

src
——common
————header
——————store
————————reducer.js

import * as constants from './constants';
import { fromJS } from 'immutable';

const defaultState = fromJS({
  focused: false
});

// ...

2.immutable 对象的获取方式

\color{red}{注意:如果获取的是列表数据结构,并且列表里面是 JS 对象}
列表循环的获取方式要改为:item.get('imgUrl'),不能为点语法,切记!!!不要忘记!!!
mapStateToProps里的获取方式为:list: state.home.get('blogList')

src
——common
————header
——————index.js

//...

const mapStateToProps = (state) => {
    return {
      focused: state.header.get('focused')
    }
}

// ...

3.immutable 对象的 set 方法会返回一个 state 的副本

src
——common
————header
——————store
————————reducer.js

//...

export default (state = defaultState, action) => {
    if (action.type === constants.SEARCH_FOCUS) {
        return state.set('focused', true);
    }
    if (action.type === constants.SEARCH_BLUR) {
        return state.set('focused', false);
    }
    return state;
};

//...

7-10 使用redux-immutable统一数据格式

list: state.home.get('blogList') => list: state.get('home').get('blogList')
=> list: state.getIn(['home', 'blogList']) \color{red}{此处获取方式的变化需注意}

npm i redux-immutable

src
——store
————reducer.js

import { combineReducers } from 'redux-immutable';

//...

src
——common
————header
——————index.js

//...

const mapStateToProps = (state) => {
    return {
      focused: state.get('header').get('focused')
    }
}

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

到这里项目中最难的部分已经搞定了,框架已经搭好
https://github.com/wtyqer/jianshu-react-framework

7-11 热门搜索样式布局

相关文章

网友评论

      本文标题:React 16.4 开发简书项目[7]

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