React 在处理小型的项目的时候是完全可以的。但是在处理复杂的项目时,React 自己是不够的。我们还需要使用redux 框架,帮助我们管理数据。
如果我们使用了redux 管理数据,那我们尽量把数据都放到redux 中进行管理。
下面,我们先把Header 组件中的focus 属性放到redux 中进行管理。
先下载安装 redux 与 react-redux
yarn add redux
yarn add react-redux
然后,我们在src 目录下新建一个目录 store。然后在store 下创建文件 index.js 在这儿新建store ,然后再新建一个文件 reducer.js 在这儿export 一个纯函数,作为 reducer。
先是 src/store/index.js 代码
import { createStore } from 'redux';
import reducer from './reducer';
const store = createStore(reducer);
export default store;
然后是reducer.js 代码
const defaultState = {};
export default (state = defaultState, action) => {
return state;
}
再,我们在App.js 中引入 store 和 react-redux,App.js 是整个项目整体解构的 js 文件。代码如下。
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { GlobalStyle } from './style.js';
import Header from './common/header';
import store from './store/index';
class App extends Component {
render() {
return (
<div>
<GlobalStyle />
<Provider store={store}>
<Header />
</Provider>
</div>
);
}
}
export default App;
然后,我们再去Header组件文件。src/common/header/index.js。在这个组件中,我们引入react-redux 的connect 。将这个组件与redux 中的store 做连接。
import React, { Component } from 'react';
import {connect} from 'react-redux';
import {
HeaderWrapper,
Logo,
Nav,
NavItem,
NavSearch,
Addition,
Button,
SearchWrapper
} from './style';
import '../../statics/iconfont/iconfont.css';
import { CSSTransition } from 'react-transition-group';
class Header extends Component {
constructor(props) {
super(props);
this.state = {
focused: false
}
this.handleFocus = this.handleFocus.bind(this);
this.handleBlur = this.handleBlur.bind(this);
}
render () {
return (
<HeaderWrapper>
<Logo href='/'/>
<Nav>
<NavItem className='left active'>首页</NavItem>
<NavItem className='left'>下载</NavItem>
<NavItem className='right'>登录</NavItem>
<NavItem className='right'>
<span className="iconfont"></span>
</NavItem>
<SearchWrapper>
<CSSTransition
in={this.state.focused}
timeout={200}
classNames="slide"
>
<NavSearch
placeholder="搜索"
className={this.state.focused ? "focused" : ""}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
></NavSearch>
</CSSTransition>
<span
className={this.state.focused ? "focused iconfont" : "iconfont"}
></span>
</SearchWrapper>
</Nav>
<Addition>
<Button className='writting'>
<span className="iconfont"></span>
写文章
</Button>
<Button className='reg'>注册</Button>
</Addition>
</HeaderWrapper>
)
}
handleFocus() {
this.setState({
focused: true
})
}
handleBlur() {
this.setState({
focused: false
})
}
}
const mapStateToProps = (state) => {
return {
}
}
const mapDispatchToProps = (dispatch) => {
return {
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Header);
然后,我们把Header 组件中的focused 属性放到store 中。
先在src/store/reducer.js 中进行如下修改。
const defaultState = {
focused: false
};
export default (state = defaultState, action) => {
return state;
}
然后,我们改一下,获取focused 的方式 mapStateToProps 变量,如下。记得改一下focused 属性的使用方式 this.props.focused
const mapStateToProps = (state) => {
return {
focused: state.focused
}
}
好的,接下来,我们来写一下修改focused 属性的方式 mapDispatchToProps 变量。同时记得改一下 输入框的 onFocus和 onBlur 事件的响应函数。如下。
import React, { Component } from 'react';
import {connect} from 'react-redux';
import {
HeaderWrapper,
Logo,
Nav,
NavItem,
NavSearch,
Addition,
Button,
SearchWrapper
} from './style';
import '../../statics/iconfont/iconfont.css';
import { CSSTransition } from 'react-transition-group';
class Header extends Component {
render () {
const { focused, handleFocus, handleBlur } = this.props;
return (
<HeaderWrapper>
<Logo href='/'/>
<Nav>
<NavItem className='left active'>首页</NavItem>
<NavItem className='left'>下载</NavItem>
<NavItem className='right'>登录</NavItem>
<NavItem className='right'>
<span className="iconfont"></span>
</NavItem>
<SearchWrapper>
<CSSTransition
in={focused}
timeout={200}
classNames="slide"
>
<NavSearch
placeholder="搜索"
className={focused ? "focused" : ""}
onFocus={handleFocus}
onBlur={handleBlur}
></NavSearch>
</CSSTransition>
<span
className={focused ? "focused iconfont" : "iconfont"}
></span>
</SearchWrapper>
</Nav>
<Addition>
<Button className='writting'>
<span className="iconfont"></span>
写文章
</Button>
<Button className='reg'>注册</Button>
</Addition>
</HeaderWrapper>
)
}
}
const mapStateToProps = (state) => {
return {
focused: state.focused
}
}
const mapDispatchToProps = (dispatch) => {
return {
handleFocus () {
const action = {
type: "search_focus",
};
dispatch(action);
},
handleBlur () {
const action = {
type: "search_blur",
};
dispatch(action);
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Header);
然后,我们再来改一下reducer.js 。如下。
const defaultState = {
focused: false
};
export default (state = defaultState, action) => {
if (action.type === "search_focus") {
let newState = JSON.parse(JSON.stringify(state));
newState.focused = true;
return newState;
}
if (action.type === "search_blur") {
let newState = JSON.parse(JSON.stringify(state));
newState.focused = false;
return newState;
}
return state;
}
好了。
这个时候,我们可以看到,Header 组件,变成了只有render 函数的组件,因此它可以被改写为无状态组件。如下。
import React, { Component } from 'react';
import {connect} from 'react-redux';
import {
HeaderWrapper,
Logo,
Nav,
NavItem,
NavSearch,
Addition,
Button,
SearchWrapper
} from './style';
import '../../statics/iconfont/iconfont.css';
import { CSSTransition } from 'react-transition-group';
const Header = (props) => {
return (
<HeaderWrapper>
<Logo href='/'/>
<Nav>
<NavItem className='left active'>首页</NavItem>
<NavItem className='left'>下载</NavItem>
<NavItem className='right'>登录</NavItem>
<NavItem className='right'>
<span className="iconfont"></span>
</NavItem>
<SearchWrapper>
<CSSTransition
in={props.focused}
timeout={200}
classNames="slide"
>
<NavSearch
placeholder="搜索"
className={props.focused ? "focused" : ""}
onFocus={props.handleFocus}
onBlur={props.handleBlur}
></NavSearch>
</CSSTransition>
<span
className={props.focused ? "focused iconfont" : "iconfont"}
></span>
</SearchWrapper>
</Nav>
<Addition>
<Button className='writting'>
<span className="iconfont"></span>
写文章
</Button>
<Button className='reg'>注册</Button>
</Addition>
</HeaderWrapper>
)
}
const mapStateToProps = (state) => {
return {
focused: state.focused
}
}
const mapDispatchToProps = (dispatch) => {
return {
handleFocus () {
const action = {
type: "search_focus",
};
dispatch(action);
},
handleBlur () {
const action = {
type: "search_blur",
};
dispatch(action);
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Header);
Done.