一、需求描述及分析
在一个页面中有三个组件,分别为Header、List以及AddForm,它们是兄弟组件,要求:
Header组件中有两个按钮(一个同步一个异步)可以打开AddForm(默认AddForm隐藏不显示)AddForm有一个按钮可以关闭自身AddForm中有输入框,可以添加数据到List组件List可以显示数据
需求中的数据流如下图所示:
二、案例实操
1. 安装依赖
npm install redux
- 安装react-redux(用于实现React中的props与redux的映射)
npm install react-redux
- 安装redux-thunk(用于支持异步action)
npm install --save redux-thunk
- 安装redux-devtools-extension(用于在开发者工具中查看状态变化)
npm install redux-devtools-extension -D
2. 项目目录
3. 准备action的type名称的常量
constant.js
export const OPEN_FORM = 'openForm'
export const CLOSE_FORM = 'closeForm'
export const ADD_DATA = 'addData'
4. 编写action的生产工厂
src\store\actions\form.js
import {OPEN_FORM,CLOSE_FORM} from '../constant'
export const openForm = data => ({type:OPEN_FORM,data})
export const closeForm = data => ({type:CLOSE_FORM,data})
export const openFormAsync = data => {
return (dispatch) => {
setTimeout(() => {
dispatch(openForm(data))
},2000)
}
}
src\store\actions\list.js
import {ADD_DATA} from '../constant'
export const addData = data => ({type:ADD_DATA,data})
5. 编写reducers
src\store\reducers\form.js
import {OPEN_FORM,CLOSE_FORM} from '../constant'
let initSate = {
isOpen:false
}
export default function formReducer(state=initSate,action){
console.log(action)
switch(action.type){
case OPEN_FORM:
return {...state,isOpen:true}
case CLOSE_FORM:
return {...state,isOpen:false}
default:
return state
}
}
src\store\reducers\list.js
import {ADD_DATA} from '../constant'
const initSate = {
list:[]
}
export default function listReducer(state=initSate,action){
switch(action.type){
case ADD_DATA:
return {...state,list:[...state.list,action.data]}
default:
return state
}
}
src\store\reducers\index.js
import {combineReducers} from 'redux'
import form from './form'
import list from './list'
export default combineReducers({
form,
list
})
6.编写store
src\store\store.js
import {applyMiddleware, createStore} from 'redux'
import reducer from './reducers'
import thunk from 'redux-thunk'
import {composeWithDevTools} from 'redux-devtools-extension'
export default createStore(reducer,composeWithDevTools(applyMiddleware(thunk)))
到目前为止,都是在使用Redux的提供的api,并未使用react-redux
7. 更改入口文件
src\index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import {Provider} from 'react-redux'
import store from './store/store'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
,
document.getElementById('root')
);
要使用Provider组件包裹App组件,并将store对象作为props传递进去,此api由react-redux提供
8. 编写各个组件
使用react-redux提供的connect函数将普通组件包装为容器
关于connect:
src\components\Main\Header.jsx
import React, { Component } from 'react'
import {connect} from 'react-redux'
import {openForm,openFormAsync} from '../../store/actions/form'
class Header extends Component {
openForm = () => {
this.props.openForm(null)
}
openFormAsync = () => {
this.props.openFormAsync(null)
}
render() {
return (
<div>
<h3>Header</h3>
<button onClick={this.openForm}>同步打开表单</button>
<button onClick={this.openFormAsync}>异步打开表单</button>
</div>
)
}
}
export default connect(
state => ({
}),
{openForm,openFormAsync}
)(Header)
src\components\Main\List.jsx
import React, { Component } from 'react'
import {connect} from 'react-redux'
class List extends Component {
render() {
return (
<div>
<h3>List</h3>
<ul>
{
this.props.list.map(item => {
return <li>{item}</li>
})
}
</ul>
</div>
)
}
}
export default connect(state => ({list:state.list.list})
,
{})
(List)
src\components\Main\AddForm.jsx
import React, { Component } from 'react'
import {connect} from 'react-redux'
import {closeForm} from '../../store/actions/form'
import {addData} from '../../store/actions/list'
class AddForm extends Component {
state = {
inputValue : ''
}
closeForm = () => {
this.props.closeForm(null);
}
addData = () => {
this.props.addData(this.state.inputValue)
}
handleChange = (e) => {
this.setState({inputValue:e.target.value})
}
render() {
console.log(this.props.isOpen)
if(this.props.isOpen){
return (
<div>
<h3>Form</h3>
<input onChange={e => this.handleChange(e)}/>
<button onClick={this.addData}>添加</button>
<button onClick={this.closeForm}>关闭表单</button>
</div>
)
} else {
return (
<div/>
)
}
}
}
export default connect(
state => ({
isOpen:state.form.isOpen
}),
{closeForm,addData}
)(AddForm)
AddForm组件所展示的写法更全面一些
src\components\Main\index.jsx
import React, { Component } from 'react'
import AddForm from './AddForm'
import Header from './Header'
import List from './List'
import './index.scss'
export default class Main extends Component {
render() {
return (
<div className='main'>
<Header/>
<br/>
<List/>
<br/>
<AddForm/>
</div>
)
}
}
9. 效果展示
Header控制AddForm的显示(同步+异步)
AddForm关闭自身
AddForm添加数据
使用函数钩子: